Vue實戰—實現商品詳情頁(12)

這篇我們來實現商品詳情頁面:
圖片描述

在首頁點擊某一商品會展示商品的詳細信息。如下圖所示:
圖片描述

創建good組件

創建一個組件 good

  • transition 來定義頁面展示的形式;
  • 使用v-show與變量showFlag來控制顯示與隱藏,ref配合BScroll控制頁面的滑動;
  • 現在結構內出現的數據的引用我們在script內進行處理。

    <template>
    <transition name="food-detail">

    <div class="food" v-show="showFlag" ref="foodView">
      <div class="food-wrapper">
        <div class="food-content">
          <div class="img-wrapper">
            <img class="food-img" :src="food.picture">
            
            <span class="close-bt icon-close" @click="closeView"></span>
            <img class="share-bt" src="./share.png">
            <img class="more-bt" src="./more.png">
          </div>
          <div class="content-wrapper">
            <h3 class="name">{{food.name}}</h3>
            <p class="saled">{{food.month_saled_content}}</p>
            <img
              class="product"
              v-show="food.product_label_picture"
              :src="food.product_label_picture"
            >
            <p class="price">
              <span class="text">¥{{food.min_price}}</span>
              <span class="unit">/{{food.unit}}</span>
            </p>
            <div class="cartcontrol-wrapper">
              <Cartcontrol :food="food"></Cartcontrol>
            </div>
            <div class="buy" v-show="!food.count || food.count==0" @click="addFirst">選規格</div>
          </div>
        </div>
        <div class="rating-wrapper">
          <div class="rating-title">
            <div class="like-ratio" v-if="food.rating">
              <span class="title">{{food.rating.title}}</span>
              <span class="ratio">
                (
                {{food.rating.like_ratio_desc}}
                <i>{{food.rating.like_ratio}}</i>
                )
              </span>
            </div>
            <div class="snd-title" v-if="food.rating">
              <span class="text">{{food.rating.snd_title}}</span>
              <span class="icon icon-keyboard_arrow_right"></span>
            </div>
          </div>
    
          <ul class="rating-content" v-if="food.rating">
            <li v-for="comment in food.rating.comment_list" class="comment-item">
              <div class="comment-header">
                <img :src="comment.user_icon" v-if="comment.user_icon">
                <img src="./anonymity.png" v-if="!comment.user_icon">
              </div>
              <div class="comment-main">
                <div class="user">{{comment.user_name}}</div>
                <div class="time">{{comment.comment_time}}</div>
                <div class="content">{{comment.comment_content}}</div>
              </div>
            </li>
          </ul>
        </div>
      </div>
    </div>

    </transition>
    </template>

處理數據,行爲。

  • 通過data監聽showFlag的狀態;
  • 通過props傳入父組件循環Foods而得到的food數據;
  • 方法showView()可以被父組件調用,稍後說明調用形式;
  • 方法closeView()綁定在模板退出圖標上,用於關閉頁面,重置變量showFlag爲false;
  • 方法addFirst()用來添加一個商品數量;

    <script>
    // 導入BScroll
    import BScroll from "better-scroll";
    // 導入Cartcontrol
    import Cartcontrol from "components/Cartcontrol/Cartcontrol";
    // 導入Vue
    import Vue from "vue";

    export default {
    data() {

    return {
      showFlag: false
    };

    },
    props: {

    food: {
      type: Object
    }

    },
    methods: {

    // showView方法可以被父組件調用
    showView() {
      this.showFlag = true;
      // BScroll初始化
      this.$nextTick(() => {
        if (!this.scroll) {
          this.scroll = new BScroll(this.$refs.foodView, {
            click: true
          });
        } else {
          this.scroll.refresh();
        }
      });
    },
    closeView() {
      this.showFlag = false;
    },
    addFirst() {
      Vue.set(this.food, "count", 1);
    }

    },
    components: {

    Cartcontrol,
    BScroll

    }
    };
    </script>

food組件樣式

<style>
.food {
  position: fixed;
  left: 0;
  top: 0;
  bottom: 51px;
  background: white;
  width: 100%;
  z-index: 90;
}

.food-detail-enter-active,
.food-detail-leave-active {
  transition: 1s;
}
.food-detail-enter,
.food-detail-leave-to {
  transform: translateX(100%);
}

.food .food-wrapper .food-content .img-wrapper {
  position: relative;
  width: 100%;
  height: 0;

  /* 高度如何撐開?
     在定位中,使用padding-top或padding-bottom設置爲100%,其實盒子高度會根據盒子的寬度進行計算
     */
  padding-top: 100%;
}
.food .food-wrapper .food-content .img-wrapper .food-img {
  position: absolute;
  left: 0;
  bottom: 0;
  width: 100%;
  height: 100%;
}
.food .food-wrapper .food-content .img-wrapper .close-bt {
  width: 30px;
  height: 30px;
  position: absolute;
  left: 10px;
  top: 10px;
  text-align: center;
  font-size: 30px;
  color: white;
  background: #7f7f7f;
  border-radius: 50%;
}
.food .food-wrapper .food-content .img-wrapper .share-bt,
.food .food-wrapper .food-content .img-wrapper .more-bt {
  width: 30px;
  height: 30px;
  position: absolute;
  top: 10px;
}
.food .food-wrapper .food-content .img-wrapper .share-bt {
  right: 50px;
}
.food .food-wrapper .food-content .img-wrapper .more-bt {
  right: 10px;
}

.food .food-wrapper .food-content .content-wrapper {
  padding: 0 0 16px 16px;
  position: relative;
}
.food .food-wrapper .food-content .content-wrapper .name {
  font-size: 15px;
  color: #333333;
  line-height: 30px;
  font-weight: bold;
}
.food .food-wrapper .food-content .content-wrapper .saled {
  font-size: 11px;
  color: #9d9d9d;
  margin-bottom: 6px;
}
.food .food-wrapper .food-content .content-wrapper .product {
  height: 15px;
  margin-bottom: 16px;
}
.food .food-wrapper .food-content .content-wrapper .price {
  font-size: 0;
}
.food .food-wrapper .food-content .content-wrapper .price .text {
  font-size: 17px;
  color: #fb4e44;
}
.food .food-wrapper .food-content .content-wrapper .price .unit {
  font-size: 11px;
  color: #9d9d9d;
}
.food .food-wrapper .food-content .cartcontrol-wrapper {
  position: absolute;
  right: 12px;
  bottom: 10px;
  padding: 2px;
}
.food .food-wrapper .food-content .buy {
  width: 64px;
  height: 30px;
  font-size: 12px;
  line-height: 30px;
  text-align: center;
  background: #ffd161;
  border-radius: 30px;
  position: absolute;
  right: 12px;
  bottom: 10px;
}

.food .food-wrapper .rating-wrapper {
  padding-left: 16px;
}
.food .food-wrapper .rating-wrapper .rating-title {
  padding: 16px 16px 16px 0;
}
.food .food-wrapper .rating-wrapper .rating-title .like-ratio {
  float: left;
  font-size: 0;
}
.food .food-wrapper .rating-wrapper .rating-title .like-ratio .title {
  font-size: 13px;
}
.food .food-wrapper .rating-wrapper .rating-title .like-ratio .ratio {
  font-size: 11px;
}
.food .food-wrapper .rating-wrapper .rating-title .like-ratio .ratio i {
  color: #fb4e44;
  font-size: 11px;
}

.food .food-wrapper .rating-wrapper .rating-title .snd-title {
  float: right;
  font-size: 0;
}
.food .food-wrapper .rating-wrapper .rating-title .snd-title .text,
.food .food-wrapper .rating-wrapper .rating-title .snd-title .icon {
  font-size: 13px;
  color: #9d9d9d;
  display: inline-block;
}
.food .food-wrapper .rating-wrapper .rating-title .snd-title .icon {
  margin-left: 12px;
}

.food .food-wrapper .rating-wrapper .comment-item {
  padding: 15px 14px 17px 0;
  border-bottom: 1px solid #f4f4f4;
  width: 100%;
  box-sizing: border-box;
  display: flex;
}
.food .food-wrapper .rating-wrapper .comment-item .comment-header {
  flex: 0 0 41px;
  margin-right: 10px;
}
.food .food-wrapper .rating-wrapper .comment-item .comment-header img {
  width: 41px;
  height: 41px;
  border-radius: 50%;
}

.food .food-wrapper .rating-wrapper .comment-item .comment-main {
  flex: 1;
  margin-top: 6px;
}
.food .food-wrapper .rating-wrapper .comment-item .comment-main .user {
  width: 50%;
  float: left;
  font-size: 12px;
  color: #333333;
}
.food .food-wrapper .rating-wrapper .comment-item .comment-main .time {
  width: 50%;
  float: right;
  text-align: right;
  font-size: 10px;
  color: #666666;
}
.food .food-wrapper .rating-wrapper .comment-item .comment-main .content {
  margin-top: 17px;
  font-size: 13px;
  line-height: 19px;
}
</style>


在foods父組件內引用food組件

父組件中,selectedFood變量 默認沒有選中任何商品

當我們通過showDetail()點擊商品時候將所選擇的food傳入selectedFood;

通過父組件模板中ref="foodView與script標籤內 this.$refs.foodView.showView(),調用子組件的方法顯示詳情頁面。

注意變量名稱不要與事件名稱重複。方法名稱與data一樣的話,都可以通過this訪問,會有覆蓋風險。所以不要重複。

<template>
    <!--foods組件其他內容-->
    

    <!--商品詳情-->
    <Food :food="selectedFood" ref="foodView"></Food>

</template>



<script>
    // 導入Food
    import Food from "components/Food/Food";
    // 導入Cartcontrol
    import Cartcontrol from "components/Cartcontrol/Cartcontrol";
    

 export default {
     data() {
        return {
              selectedFood: {}
        };
     },
     methods:{
         showDetail(food) {
              // 傳值
              this.selectedFood = food;

              // 顯示詳情頁
              this.$refs.foodView.showView();
        }
     }
 }
    

</script>

圖片描述
總結

我們先創建了good組件,定義了所依賴的數據,方法,

注意子組件的方法可以被父組件調用,我們瞭解父組件中調用子組件中的方法的方式。但是子組件不可以調用父組件的方法。

然後我們在父組件foods中引用了子組件。有個細節data中的變量名不要與方法名字重複,避免被this.xx訪問到,從而覆蓋掉,產生錯誤。我們也瞭解父組件調用子組件方法的方式。

如上圖所示,我們實現了商品詳情頁。

下一篇我們來實現商品詳情頁面中的評價列表。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章