和之前一样,我们将该组件要使用的数据封装进一个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; }, }