商品参数信息在返回data中的分布也很松散,将它们整合为一个类GoodsParam,然后将数据保存在GoodsParam的实例paramsInfo中,发送给子组件DetailParamsInfo:
export class GoodsParam{ constructor(info,rule) { this.image = info.images ? info.images[0] : ''; this.infos = info.set; this.sizes = rule.tables; } }
this.paramsInfo = new GoodsParam( data.itemParams.info, data.itemParams.rule );
<detail-params-info :param-info="paramsInfo" ref="params"></detail-params-info>
接下来就是布局的工作了,没有什么难点,无非是使用v-for来生成表格以及表格的每一行:
1 <template> 2 <div class="param-info" v-if="Object.keys(paramInfo).length !== 0"> 3 4 <table v-for="(table, index) in paramInfo.sizes" 5 class="info-size" :key="index"> 6 <tr v-for="(tr, indey) in table" :key="indey"> 7 <td v-for="(td, indez) in tr" :key="indez">{{td}}</td> 8 </tr> 9 </table> 10 11 <table class="info-param"> 12 <tr v-for="(info, index) in paramInfo.infos" :key="index"> 13 <td class="info-param-key">{{info.key}}</td> 14 <td class="param-value">{{info.value}}</td> 15 </tr> 16 </table> 17 <div class="info-img" v-if="paramInfo.image.length !== 0"> 18 <img :src="paramInfo.image" alt=""> 19 </div> 20 </div> 21 </template>
评论信息的显示:首先判断该商品下是否有评论,有则获取,并将其发送给DetailCommentInfo组件:
// 6、获取评论信息 if (data.rate.cRate !== 0) { this.commentInfo = data.rate.list[0]; }
<detail-comment-info :comment-info="commentInfo" ref="comment"></detail-comment-info>
剩下的布局,除了一个关于日期格式化的过滤器,其它都很好理解:
<template> <div v-if="Object.keys(commentInfo).length !== 0" class="comment-info"> <div class="info-header"> <div class="header-title">用户评价</div> <div class="header-more">更多</div> </div> <div class="info-user"> <img :src="commentInfo.user.avatar" alt="" /> <span>{{ commentInfo.user.uname }}</span> </div> <div class="info-detail"> <p>{{ commentInfo.content }}</p> <div class="info-other"> <span class="date">{{ commentInfo.created | showDate }}</span> <span>{{ commentInfo.style }}</span> </div> <div class="info-imgs"> <img :src="item" v-for="(item, index) in commentInfo.images" :key="index" /> </div> </div> </div> </template>
可以看到这个showDate过滤器以commentInfo.created为参数,定义如下:
filters: { showDate(value) { let date = new Date(value * 1000); return formatDate(date, "yyyy-MM-dd hh:mm:ss"); }, }
commentInfo.created为一串时间戳,如:1537791634。它表示UTC时间,扩大1000倍后转化为毫秒表示。showDate中先将时间戳转化为Date对象,再通过调用formatDate函数,让Date对象按照第二个参数指定的日期格式进行显示。下面解析一下formatDate函数的代码,顺便对Date对象做个总结:
export function formatDate(date, fmt) { if (/(y+)/.test(fmt)) { fmt = fmt.replace(RegExp.$1, (date.getFullYear() + '').substr(4 - RegExp.$1.length)); } let o = { 'M+': date.getMonth() + 1, 'd+': date.getDate(), 'h+': date.getHours(), 'm+': date.getMinutes(), 's+': date.getSeconds() }; for (let k in o) { if (new RegExp(`(${k})`).test(fmt)) { let str = o[k] + ''; fmt = fmt.replace(RegExp.$1, (RegExp.$1.length === 1) ? str : padLeftZero(str)); } } return fmt; }; function padLeftZero (str) { return ('00' + str).substr(str.length); };
1、如果指定格式fmt中匹配到一个或多个y,则将第一个捕获组RegExp.$1替换为date中的年份。先调用getFullYear()获取年份,再将其转换为字符串,最后通过substr方法将年份截取为合适的长度。
2、后面的月日时分秒的匹配类似,所以定义一个对象o,通过遍历o属性完成对其余单位的匹配。如果捕获组的长度大于1,则通过padLeftZero为其补零。
(str两位 原样返回;15 0015 ;str一位 补一个零:5 005)