Vue实战—评价组件的设计与实现(6)
栏目: JavaScript · 发布时间: 6年前
内容简介:在上篇文章我们将项目头部模块进行了编写与数据渲染。本篇文章我们进一步深入项目设计评价组件。
在上篇文章我们将项目头部模块进行了编写与数据渲染。
本篇文章我们进一步深入项目设计评价组件。
分析页面
如图所示,点菜,评价,商家,为导航,我们点击评价的时候,直接跳转评价页面。
评价页面由商家评分一栏,评论列表构成,评论列表支持:全部,有图,点评三种筛选。
综上我们现在开始设计评论组件:
建立组件文件夹
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)
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
ANSI Common Lisp
Paul Graham / Prentice Hall / 1995-11-12 / USD 116.40
For use as a core text supplement in any course covering common LISP such as Artificial Intelligence or Concepts of Programming Languages. Teaching students new and more powerful ways of thinking abo......一起来看看 《ANSI Common Lisp》 这本书的介绍吧!