首先编写ratings,要用到betterScroll
<template>
<div class="ratings" ref="ratings"> <!-- ratings-content大于ratings的时候出现滚动 -->
<div class="ratings-content">
并添加样式:
和good组件一样,我们要固定视口的高度,所以将其定位绝对定位,top为header组件的高度
.ratings
position absolute
top 174px
bottom 0
left 0
width 100%
overflow hidden
接下来编写overview部分,左边是综合评分,右边是star组件+商品评分+送达时间,下边是左侧部分的样式
<div class="ratings-content">
<div class="overview">
<div class="overview-left">
<h1 class="score">{{seller.score}}</h1>
<div class="title">综合评分</div>
<div class="rank">高于周边商家{{seller.rankRate}}%</div>
</div>
<div class="overview-right">
.....
</div>
</div>
<split></split>
其中,seller的数据由App.vue中的routerview进行传递,在rating组件中使用props进行接收,这样在模板中就可以直接引用seller的数据了
props: {
seller: {
type: Object
}
}
添加CSS样式:左侧部分
.overview
display flex
padding 18px 0 18px 18px
.overview-left
padding-bottom 6px 0
flex 0 0 137px
width 137px // 防止出现兼容性问题
border-right 1px solid rgba(7,17,27,0.1)
text-align center
@media only screen and (max-width 320px)
flex 0 0 110px
width 110px
.score
margin-bottom 6px
line-height 28px
font-size 24px
color rgb(255, 153, 0)
.title
margin-bottom 8px
line-height 12px
font-size 12px
color rgb(7, 17, 27)
.rank
line-height 10px
font-size 10px
color rgb(147, 153, 159)
.overview-right
flex 1
padding 6px 0 6px 24px
接下来填充坐左侧部分的样式,先写布局,不要忘记引入并注册star组件,尺寸是36的
<div class="overview">
<div class="overview-left">
...
</div>
<div class="overview-right">
<div class="score-wrapper">
<span class="title">服务态度</span>
<star :size="36" :score="seller.serviceScore"></star>
<span class="score">{{seller.serviceScore}}</span>
</div>
<div class="score-wrapper">
<span class="title">商品评分</span>
<star :size="36" :score="seller.foodScore"></star>
<span class="score">{{seller.foodScore}}</span>
</div>
<div class="delivery-wrapper">
<span class="title">送达时间</span>
<span class="delivery">{{seller.deliveryTime}}分钟</span>
</div>
</div>
</div>
之后,为右侧部分添加布局
.overview-right
flex 1
padding 6px 0 6px 24px
@media only screen and (max-width 320px)
padding-left 6px
.score-wrapper
line-height 18px
margin-top 8px
font-size 0
.title
display inline-block
vertical-align top
line-height 18px
font-size 12px
color rgb(7, 17, 27)
.star
display inline-block
vertical-align top
margin 0 12px
.score
display inline-block
vertical-align top
line-height 18px
font-size 12px
color rgb(255, 153, 0)
.delivery-wrapper
font-size 0
.title //span文字和文字之间默认是垂直居中的,可以不用加display vertical-align
display inline-block
vertical-align top
line-height 18px
font-size 12px
color rgb(7, 17, 27)
.delivery
display inline-block
margin-left 12px
vertical-align top
line-height 18px
font-size 12px
color rgb(147, 153, 159)
还有一个问题,当屏幕宽度变短时,右侧部分过长会出现折行,这不是想要的,添加一个mediea Query即媒体查询进行解决
.overview-left
padding-bottom 6px 0
flex 0 0 137px
width 137px // 防止出现兼容性问题
border-right 1px solid rgba(7,17,27,0.1)
text-align center
@media only screen and (max-width 320px)
flex 0 0 110px
width 110px
.overview-right
flex 1
padding 6px 0 6px 24px
@media only screen and (max-width 320px)
padding-left 6px
4)引入并注册split.vue和ratingselect.vue组件中调用
<split></split>
<ratingselect @increment="incrementTotal" :select-type="selectType" :only-content="onlyContent" :ratings="ratings"></ratingselect>
现在data中添加ratingselect组件中需要维护的值,上边模板中的ratings是所有商品的ratings,不是一种商品的food.ratings
5)food.vue和rating.vue都将评价类型或者是选择类型传递给ratingselect.vue组件,但是传递的数值是不一样的,在这里,:ratings="ratings",指的是随商家的评价,在foods.vue中是:ratings="food.ratings",是对商家店里某一种食物的评价
data () {
return {
ratings: [],
showFlag: false,
selectType: ALL,
onlyContent: true
};
}
6)同goods.vue,在created()函数中拿到rating的API数据,将得到的ratings传到raqtings的组件中
created() {
//请求的ajex地址,成功的回调,拿到一个response
this.$http.get('/api/ratings').then((response) => {
//response是一个属性,将其转化为json对象
response = response.body;
//console.log(response);
if (response.errno === ERR_OK) {
// 数据在data字段中,将goods对象传给header组件,通过:goods
this.ratings = response.data;
// console.log(this.goods);
this.$nextTick(() => {
this.scroll = new BScroll(this.$refs.ratings, {
click: true //允许点击
});
});
}
});
},
7)拿到数据之后在raring组件中编写样式,填充html中的DOM数据
<div class="rating-wrapper">
<ul>
<li v-for="rating in ratings" :key="rating.id" class="rating-item" v-show="needShow(rating.rateType, rating.text)">
<div class="avatar">
<img :src="rating.avatar" width="28px" height="28px">
</div>
<div class="content">
<h1 class="name">{{rating.username}}</h1>
<div class="star-wrapper">
<star :size="24" :score="rating.score"></star>
<span class="delivery" v-show="rating.deliveryTime">
{{rating.deliveryTime}}
</span>
</div>
<p class="text">{{rating.text}}</p>
<div class="recommend" v-show="rating.recommend && rating.recommend.length"> <!-- 赞或踩和相关推荐 -->
<i class="icon-thumb_up"></i>
<span class="item" v-for="item in rating.recommend" :key="item.id">{{item}}</span>
</div>
<div class="time">
{{rating.rateTime | formatDate}}
</div>
</div>
</li>
</ul>
</div>
完成样式:
.rating-wrapper
padding 0 18px
.rating-item
display flex
padding 18px 0
border-1px(rgba(1, 17, 27, 0.1))
.avatar
flex 0 0 28px
width 28px
margin-right 12px
img
border-radius 50%
.content
position relative
flex 1
.name
margin-bottom 4px
line-height 12px
font-weight 700
font-size 10px
color rgb(7, 17, 27)
.star-wrapper
margin-bottom 6px
font-size 0
.star
display inline-block
margin-right 16px
vertical-align top
.delivery
display inline-block
vertical-align top
font-size 10px
line-height 12px
color rgb(147, 153, 159)
.text
line-height 18px
color rgb(7, 17, 27)
font-size 12px
margin-bottom 8px
.recommend
line-height 16px
font-size 0
.icon-thumb_up, .item
display inline-block
margin 0 8px 4px 0
font-size 9px
.icon-thumb_up
color rgb(0, 160, 220)
.item
padding 0 6px
border 1px solid rgba(7, 17, 27, 0.1)
border-radius 1px
color rgb(147, 153, 159)
background #fffff
.time
position absolute
top 0
right 0
line-height 12px
font-size 10px
color rgb(147, 153, 159)
8)绑定BScroll进行滚动
8.1 拿到DOM数据,ref="ratings",将BS初始化写在created函数拿到api数据之后
8.2.默认进图商品界面还会导致rating界面来不及渲染,因为nextTicks是异步执行的,所以将默认进入商品界面去除
在main.js中//router.push('/goods'); // 默认进入商家页面
8.3 .点击切换评价列表,和商品详情页类似,引入子组件
<ratingselect @increment="incrementTotal" :select-type="selectType" :only-content="onlyContent" :ratings="ratings"></ratingselect>
子组件已经定义好了data数据和派发函数,在food详情页展示的时候已经写过了
data() {
return {
sType: this.selectType,
oContent: this.onlyContent,
}
},
<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>
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);
}
},
在父组件rating.vue中
incrementTotal(type, data) {
this[type] = data;
this.$nextTick(() => {
this.scroll.refresh();
});
},
9. 点击满意不满意和只看内容的评价,评价列表进行刷新,在li列表展示里添加needshow();,needshow中改变的是selectType的值
<div class="rating-wrapper">
<ul>
<li v-for="rating in ratings" :key="rating.id" class="rating-item" v-show="needShow(rating.rateType, rating.text)">
incrementTotal(type, data) {
this[type] = data;
this.$nextTick(() => {
this.scroll.refresh();
});
},
needShow(type, text) {
if (this.onlyContent && !text) {
return false;
}
if (this.selectType === ALL) {
return true;
} else {
return type === this.selectType;
}
}
}