ratingselect组件的实现
1)创建ratingselect文件和ratingselect.vue
2)设置ratingselect组件中需要的props接收的数据,数据应从food.vue组件传入<ratingselect></ratingselect>,并由ratingselect.vue的props接收
const POSITIVE = 0;
const NEGATIVE = 1;
const ALL = 2;
export default {
//需要一些评价数据才能完成评价组件
props: {
ratings: {
type: Array,
default() {
return [];
}
},
selectType: { //全部,满意,不满意
type: Number,
default: ALL //默认情况时ALL,值等于2
},
onlyContent: { //只看有内容的评价还是所有的评价
type: Boolean,
default: false //设置为可以看到所有的评价
},
desc: { //描述
type: Object,
default() { //默认desc是这三种,在商品详情页的时候传入推荐或者吐槽
return {
all: '全部',
positive: '满意',
negative: '不满意'
};
}
}
},
3)food.vue中,在foods组件中引入并注册ratingselect.vue组件,并data属性和(:)属性将2)中需要的数据从foods组件中传到ratingselect.vue组件的props中
data () {
return {
showFlag: false,
selectType: ALL,
onlyContent: false, //先设置组件一开始显示有内容的评价
desc: { //desc做了改变
all: '全部',
positive: '推荐',
negative: '吐槽'
}
};
},
<!-- ratings对应被点击的food的ratings-->
<ratingselect @increment="incrementTotal" :select-type="selectType" :only-content="onlyContent" :desc="desc" :ratings="food.ratings"></ratingselect>
此时,desc已经从默认的满意和不满意变成了推荐和吐槽,接下来在foods.vue中为title和ratingselect部分编写样式和ratingselect自身样式的编写(ratingType和switch的普通样式和点击时的样式变化,若要改变初始状态就在food.vue中的show()函数中改变,show()函数是用来被goods.vue调用并展开详情界面的
<template>
<div class="ratingselect">
<div class="rating-type" border-1px>
<span class="block positive" @click="select(2,$event)" :class="{'active':sType === 2}">{{desc.all}}<span class="count">{{ratings.length}}</span> </span>
<span class="block positive" @click="select(0,$event)" :class="{'active':sType === 0}">{{desc.positive}}<span class="count">{{positives.length}}</span></span>
<span class="block negative" @click="select(1,$event)" :class="{'active':sType === 1}">{{desc.negative}}<span class="count">{{negatives.length}}</span></span>
</div>
<div @click="toggleContent($event)" class="switch" :class="{'on':oContent}">
<span class="icon-check_circle"></span>
<span class="text">只看有内容的评价</span>
</div>
</div>
</template>
.ratingselect
.rating-type
padding 18px 0
margin 0 18px //保证横线的长度
border-1px(rgba(7,17,27,0.1))
font-size 0
.block //没有写文字的时候是没有被撑开的
display inline-block
padding 8px 12px
margin-right 8px
border-radius 1px
line-height 16px
font-size 12px
color rgb(77,85,93)
&.active // block的active要设置一下
color #ffffff
.count
margin-left 2px
font-size 8px
&.positive
background rgba(0,160,220,.2)
&.active
background rgb(0,160,220)
&.negative
background rgba(77,85,93,0.2)
&.active
background rgb(77,85,93)
.switch
padding 12px 18px
line-height 24px
border-bottom 1px solid rgba(7,17,27,0.1)
color rgb(147,153,159)
font-size 0
&.on
.icon-check_circle
color #00c850
.icon-check_circle
display inline-block
vertical-align top
margin-right 4px
font-size 24px
.text
display inline-block
vertical-align top
font-size 12px
</style>
4)为ratingType(是否满意)和switch(是否查看全部评估)编写点击事件,ratingselect.vue在select()中改变了selectType的值,要将改变的值通知到父组件food.vue的show()方法,可以通过派发事件完成
在ratingselect中重新定义变量接收父组件food传过来的值
food.vue 将selectType和onlyContent传入子组件
<ratingselect @increment="incrementTotal" :select-type="selectType" :only-content="onlyContent" :desc="desc" :ratings="food.ratings"></ratingselect>
子组件在data中定义新的变量接收接收:
data() {
return {
sType: this.selectType,
oContent: this.onlyContent,
}
},
methods: {
select (type, event) { //点击的时候外层是有一个BScroll的,所以要传递event阻止默认点击
if (!event._constructed) { //浏览器直接return掉,去掉自带click事件的点击
return;
}
//将this.selectType设置成传入的参数,而不是food传过来的初始化的值,之后样式就可以随着点击改变了
this.sType = type;
//派发事件通知父组件food.vue selectType的改变,将type值传出去
console.log('ratingselect.vue ' + type);
//this.$emit('se-type', type);
this.$emit('increment', 'selectType', this.sType);
},
toggleContent (event) {
if (!event._constructed) { //浏览器直接return掉,去掉自带click事件的点击
return;
}
this.oContent = !this.oContent;
console.log('ratingselect.vue ' + this.oContent);
// this.$emit('toggle-content', this.oContent);
this.$emit('increment', 'onlyContent', this.oContent);
}
},
回到父组件food.vue中编写监听函数,并关联组件
incrementTotal(type, data) {
this[type] = data;
this.$nextTick(() => {
this.scroll.refresh();
});
},
<ratingselect @increment="incrementTotal" :select-type="selectType" :only-content="onlyContent" :desc="desc" :ratings="food.ratings"></ratingselect>
5)统计不同评价的数量(过滤评价类型),添加positives和negitives数组,长度即为评价数量
<div class="rating-type" border-1px>
<span class="block positive" @click="select(2,$event)" :class="{'active':sType === 2}">{{desc.all}}<span class="count">{{ratings.length}}</span> </span>
<span class="block positive" @click="select(0,$event)" :class="{'active':sType === 0}">{{desc.positive}}<span class="count">{{positives.length}}</span></span>
<span class="block negative" @click="select(1,$event)" :class="{'active':sType === 1}">{{desc.negative}}<span class="count">{{negatives.length}}</span></span>
</div>
computed: {
positives() { //对应所有正向评价的数组
return this.ratings.filter((rating) => {
return rating.rateType === POSITIVE;
});
},
negatives() {
return this.ratings.filter((rating) => {
return rating.rateType === NEGATIVE;
});
}
},
6)为其中时间的显示添加过滤器
<div class="time">{{rating.rateTime | formatDate}}</div>
import {formatDate} from 'common/js/date.js';
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);
}
8)点击是否满意和只看有评价内容时,评价列表的显示,不是ratingselect组件的内容,写在food.vue中
<div class="rating-wrapper"> <!-- 评价列表-->
<ul v-show="food.ratings && food.ratings.length">
<li v-show="needShow(rating.rateType, rating.text)" v-for="rating in food.ratings" :key="rating.id" class="rating-item border-1px">
<div class="user">
<span class="name">{{rating.username}}</span>
<img class="avatar" height="12" width="12" :src="rating.avatar" alt="">
</div>
<div class="time">{{rating.rateTime | formatDate}}</div>
<p class="text">
<span :class="{'icon-thumb_up':rating.rateType === 0, 'icon-thumb_down':rating.rateType === 1}"></span>{{rating.text}}
</p>
</li>
</ul>
<div class="no-ratings" v-show="!food.ratings || !food.ratings.length">暂无评价</div>
</div>
利用needshow进行切换
needShow(type, text) {
// console.log('this.selectType: ' + this.selectType + ' type: ' + type + ' out ' + text);
if (this.onlyContent && !text) {
return false;
}
if (this.selectType === ALL) {
return true;
} else {
//console.log('this.selectType: ' + this.selectType + 'type: ' + type + ' in ' + text);
return type === this.selectType;
}
},