Vue实战—评价组件的设计与实现(6)
栏目: JavaScript · 发布时间: 5年前
内容简介:在上篇文章我们将项目头部模块进行了编写与数据渲染。本篇文章我们进一步深入项目设计评价组件。
在上篇文章我们将项目头部模块进行了编写与数据渲染。
本篇文章我们进一步深入项目设计评价组件。
分析页面
如图所示,点菜,评价,商家,为导航,我们点击评价的时候,直接跳转评价页面。
评价页面由商家评分一栏,评论列表构成,评论列表支持:全部,有图,点评三种筛选。
综上我们现在开始设计评论组件:
建立组件文件夹
1.css图片的存放
针对组件引用的图片可能产生变动性,我们将组件内的图片放入组件文件夹内,进行引用。使得组件更加便于维护。
2.路径配置
build/webpack.base.conf.js内:
alias: { 'vue$': 'vue/dist/vue.esm.js',//自动补全设置 '@': resolve('src'), 'components': resolve('./src/components') }
通过alias重命名设置对组件导入模块时进行了重命名。
实际在导入需要的组件写法:
// 举个例子,导入Ratings组价可以写成 import Ratings from 'components/Ratings/Ratings'
图片存放,路径配置完成以后我们建立Ratings文件夹并进入:
根据分析页面结构整理以后所以我们先把页面结构搭建出来:
在Ratings.vue中:
//设置容器存放评论组件 <template> <div class="ratings" ref='ratingView'> <div class="ratings-wrapper"> //细化我们组件 </div> </div> </template>
现在我们设计商家评分,口味,包装,等结构如下图:
<div class="overview"> <div class="overview-left"> <div class="comment-score"> <p class="score">{{ratings.comment_score}}</p> <p class="text">商家评分</p> </div> <div class="other-score"> <div class="quality-score item"> <span class="text">口味</span> <Star :score='ratings.quality_score' class='star'></Star> <span class="score">{{ratings.quality_score}}</span> </div> <div class="pack-score item"> <span class="text">包装</span> <Star :score='ratings.pack_score' class='star'></Star> <span class="score">{{ratings.pack_score}}</span> </div> </div> </div> <div class="overview-right"> <div class="delivery-score"> <p class="score">{{ratings.delivery_score}}</p> <p class="text">配送评分</p> </div> </div> </div>
实现评论中选项卡(全部,有图,点评),列表页面:
<div class="content"> <div class="rating-select" v-if="ratings.tab"> <span class="item" @click="selectTypeFn(2)" :class="{'active':selectType==2}"> {{ratings.tab[0].comment_score_title}} </span> <span class="item" @click="selectTypeFn(1)" :class="{'active':selectType==1}"> {{ratings.tab[1].comment_score_title}} </span> <span class="item" @click="selectTypeFn(0)" :class="{'active':selectType==0}"> <img src="./icon_sub_tab_dp_normal@2x.png" v-show="selectType!=0" /> <img src="./icon_sub_tab_dp_highlighted@2x.png" v-show="selectType==0" /> {{ratings.tab[2].comment_score_title}} </span> </div> <div class="labels-view"> <span v-for="item in ratings.labels" class="item" :class="{'highligh':item.label_star>0}"> {{item.content}}{{item.label_count}} </span> </div> //评论列表 <ul class="rating-list"> <li v-for="comment in selectComments" class="comment-item"> <div class="comment-header"> <img :src="comment.user_pic_url" v-if="comment.user_pic_url" /> <img src="./anonymity.png" v-if="!comment.user_pic_url" /> </div> <div class="comment-main"> <div class="user"> {{comment.user_name}} </div> <div class="time"> {{fotmatDate(comment.comment_time)}} </div> <div class="star-wrapper"> <span class="text">评分</span> <Star :score='comment.order_comment_score' class='star'></Star> </div> <div class="c_content" v-html="commentStr(comment.comment)"></div> <div class="img-wrapper" v-if="comment.comment_pics.length"> <img v-for="item in comment.comment_pics" :src="item.thumbnail_url" /> </div> </div> </li> </ul> </div>
结构搭建完成,下面我们为组件传入对应的数据。
父子组件通信
Ratings.vue
导入依赖的子组件:
<script> // 导入Star组件 import Star from 'components/Star/Star' // 导入Split组件 import Split from 'components/Split/Split' // 导入BScroll组件 import BScroll from 'better-scroll'; </script> //设置选项卡变量 const ALL = 2; // 全部 const PICTURE = 1; // 带图片 const COMMENT = 0; // 点评
下面我们开始初始化data,在created钩子内发起请求。
ratings数据部分展示:
export default { data() { return { ratings: {},//存放请求到的数据 selectType: ALL,//默认展示全部 } }, created() { // 通过axios发起get请求 let that = this; this.$axios.get('/api/ratings') .then(function(response) { // 获取到数据 var dataSource = response.data; if(dataSource.code == 0) { that.ratings = dataSource.data;//将请求到的数据引用到data()中 // 初始化滚动 that.$nextTick(() => { if(!that.scroll) { that.scroll = new BScroll(that.$refs.ratingView, { click: true }); } else { that.scroll.refresh(); } }); } }) .catch(function(error) { // 出错处理 console.log(error); }); } } </script>
注意$refs与设置容器中的ref='ratingView'我们用BScroll来操作dom,所以使用了vue的ref API
https://cn.vuejs.org/v2/api/#ref
methods: { selectTypeFn(type) { this.selectType = type; // 刷新操作 this.$nextTick(() => { this.scroll.refresh(); }); }, fotmatDate(time) { let date = new Date(time * 1000); // 时间格式 let fmt = 'yyyy.MM.dd'; if(/(y+)/.test(fmt)) { // 年 let year = date.getFullYear().toString(); fmt = fmt.replace(RegExp.$1, year); } if(/(M+)/.test(fmt)) { // 月 let mouth = date.getMonth() + 1; if(mouth < 10) { mouth = '0' + mouth; } fmt = fmt.replace(RegExp.$1, mouth); } if(/(d+)/.test(fmt)) { // 日 let mydate = date.getDate(); if(mydate < 10) { mydate = '0' + mydate; } fmt = fmt.replace(RegExp.$1, mydate); } return fmt; }, commentStr(content) { let rel = /#[^#]+#/g; return content.replace(rel, '<i>$&</i>'); } }
在methods中我们定义:
- selectTypeFn(type) 在template中点击事件执行的切换函数;
- fotmatDate(time)设置时间展示格式函数;
- commentStr(content)插入文本函数;
注意selectTypeFn函数内在我们点击对应的选项卡后使用 $nextTick()条用scroll刷新列表;
$nextTick() https://cn.vuejs.org/v2/guide...
通过计算属性将数据传入class为rating-list模板中:
- selectType的值决定了评论列表展示的数据内容
需要再次注意方法与计算属性调用方法等区别,之前我们对比过,需要详细了解,还请阅读之前文章,或官方文档。
computed: { selectComments() { if(this.selectType == ALL) { // 全部 return this.ratings.comments; } else if(this.selectType == PICTURE) { // 有图 let arr = []; this.ratings.comments.forEach((comment) => { if(comment.comment_pics.length) { arr.push(comment); } }); return arr; } else { // 点评 return this.ratings.comments_dp.comments; } } },
使用引入的组件:
components: { Star, Split, BScroll }
Split组件就是上图标记的分隔线。
星级评分的逻辑实现
新建Star文件
星星展示形式为 全星,半星,无星 通过for循环搭建好star结构:
<template> <div class="star"> <!-- itemClass: on、half、off --> <span v-for="itemClass in itemClasses" :class="itemClass" class="star-item"> </span> </div> </template>
通过props接受父组件传来的score值,并在star内使用,
通过计算属性对star内的score进行处理,
<script> // 星星长度 const LENGTH = 5; // 星星对应class const CLS_ON = 'on'; const CLS_HALF = 'half'; const CLS_OFF = 'off'; export default{ props: {//通过父组件传入score,并且在star组件内作为“data()”使用 score: { type: Number//指定类型 数字 } }, computed: { itemClasses() { let result = []; // 4.7 => 4.5 3.9 => 3.5 4.1 => 4.0 // 对分数进行处理,向下取0.5的倍数 let score = Math.floor(this.score*2) / 2; // 小数,控制半星 let hasDecimal = score % 1 !== 0; // 整数,控制全星 let integer = Math.floor(score); // 全星 for (let i=0; i<integer; i++) { result.push(CLS_ON); } // 半星 if(hasDecimal){ result.push(CLS_HALF); } // 补齐 while(result.length < LENGTH){ result.push(CLS_OFF); } return result; } } } </script>
到此我们从评价组件的页面分析,拆出了合理的模板结构,接着配置图片,组件引用的路径,节省了我们在开发中的时间,最后也是最重要的是数据的渲染,以及星级评分的实现。过程中,我们再次加深对vue的props,methods,computed,$nextTick()等理解。
以上就是本篇全部内容,下篇我们将会细化商品展示页面,我们下篇见。
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- 实战Vue组件和Mixins
- Go 设计模式实战之并发组件
- iOS 组件化实战篇(私有库)
- Android组件化方案及组件消息总线modular-event实战
- 不一样的 vue 实战 (3): 布局与组件
- 「小程序JAVA实战」小程序开源搜索组件(52)
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。