和之前一样,我们将该组件要使用的数据封装进一个Shop类:

this.shop = new Shop(data.shopInfo);
export class Shop{
  constructor(shopInfo){
    this.logo = shopInfo.shopLogo
    this.name = shopInfo.name
    this.fans = shopInfo.cFans
    this.sells = shopInfo.cSells
    this.score = shopInfo.score
    this.goodsCount = shopInfo.cGoods
  }
}

将shop保存的数据发送给DetailShopInfo组件:

<detail-shop-info :shop="shop"></detail-shop-info>

下面就剩下了布局的工作:

 1 <template>
 2   <div class="shop-info">
 3     <div class="shop-top">
 4       <img :src="shop.logo" />
 5       <span class="title">{{ shop.name }}</span>
 6     </div>
 7     <div class="shop-middle">
 8       <div class="shop-middle-item shop-middle-left">
 9         <div class="info-sells">
10           <div class="sells-count">
11             {{ shop.sells | sellCountFilter }}
12           </div>
13           <div class="sells-text">总销量</div>
14         </div>
15         <div class="info-goods">
16           <div class="goods-count">
17             {{ shop.goodsCount }}
18           </div>
19           <div class="goods-text">全部宝贝</div>
20         </div>
21       </div>
22       <div class="shop-middle-item shop-middle-right">
23         <table>
24           <tr v-for="(item, index) in shop.score" :key="index">
25             <td>{{ item.name }}</td>
26             <td class="score" :class="{ 'score-better': item.isBetter }">
27               {{ item.score }}
28             </td>
29             <td class="better" :class="{ 'better-more': item.isBetter }">
30               <span>{{ item.isBetter ? "高" : "低" }}</span>
31             </td>
32           </tr>
33         </table>
34       </div>
35     </div>
36     <div class="shop-bottom">
37       <div class="enter-shop">进店逛逛</div>
38     </div>
39   </div>
40 </template>

布局中运用了一些知识点,比如第11行的mustache表达式中使用了过滤器,过滤器通常用于格式化显示。这里的sellCountFilter以shop.sells为参数,定义如下:如果销量小于10000,则直接显示数据;如果销量大于10000,则以“万”为单位,保留两位有效数字。

  filters: {
    sellCountFilter: function (value) {
      if (value < 10000) return value;
      return (value / 10000).toFixed(2) + "万";
    },
  }

第23行到第33行以表格形式展示了店铺的各个指标得分。每个指标占一行,每行包括三列:指标名、得分、与平均分的对比。通过v-for遍历生成表格,每次生成一行,用到了动态绑定样式的知识。

 

接下来要展示的是商品的一些大图片——先获取数据、再发送数据给子组件:

//  4、保存商品详情数据
      this.detailInfo = data.detailInfo;
    <detail-goods-info :detail-info="detailInfo" @imageload="imageLoad" class="goods-info"></detail-goods-info>

布局如下:

<template>
  <div v-if="Object.keys(detailInfo).length !== 0" class="goods-info">
    <div class="info-desc clear-fix">
      <div class="start"></div>
      <div class="desc">{{ detailInfo.desc }}</div>
      <div class="end"></div>
    </div>
    <div class="info-key">{{ detailInfo.detailImage[0].key }}</div>
    <div class="info-list">
      <img
        v-for="(item, index) in detailInfo.detailImage[0].list"
        :src="item"
        alt=""
        @load="imgLoad"
        :key="index"
      />
    </div>
  </div>
</template>

前面的div都是显示一些商品的补充信息,重点是下面vfor遍历生成的img,不难看出,detailInfo.detailImage[0].list是个数组,其中存放着要显示大图的url。

我们前面说过,多张图片的加载是最耗时的,一般后续操作都要放在图片加载完成后。所以这里当最后一张图片加载完后,也要向外发送一个事件:

    imgLoad() {
      if (++this.counter === this.imagesLength) {
        this.$emit("imageload");
      }
    }

每加载一张图片,counter便加1,直到counter等于图片总数时,再告诉父组件我们加载完成了。

imagesLength在一个监视器中进行赋值,这样保证传入的detailInfo发生变化时,imagesLength可以立刻完成响应式更新。

  watch: {
    detailInfo() {
      this.imagesLength = this.detailInfo.detailImage[0].list.length;
    },
  }

 

posted on 2021-06-29 18:01  springxxxx  阅读(111)  评论(0编辑  收藏  举报