ood采用fixed布局,z-index小于shopcart和list-mask的z-index,也就是说在商品详情页还是可以显示购物车清单页。
.food
position: fixed
left: 0
top: 0
bottom: 48px
z-index: 30
100%
background: #fff
&.move-enter-active, &.move-leave-active
transition: all 0.2s
&.move-enter, &.move-leave-to
transform: translate3d(100%, 0, 0)
vue组件中data中的数据的名称和methods中的方法的名字不能相同。如果重名的话,有一个会被覆盖。父组件可以调用子组件的方法,但是子组件不能调用父组件的方法。在food组件定义一个show方法,在父组件goods中调用。
food中的图片宽高是相等的,我们利用padding-top:100%来实现,padding-top是相对于width来设置的
<div class="image-header">
<img :src="food.image">
</div>
.image-header
position: relative
100%
height: 0
padding-top: 100%
img
position: absolute
top: 0
left: 0
100%
height: 100%
ratingselect组件
ratingselect组件从父组件接收一些数据,ratings,selectType,onlyContent和desc(props中的数组和对象默认值都是一个函数)
type: Object,
default() {
return {
all: '全部',
positive: '满意',
negative: '不满意'
};
}
对于不同food的ratingselect组件,我们希望他们有相同的初始状态,因此虽然在data()中虽然已经设置了参数的默认值,在show()函数中还会对selectType和onlyContent初始化
show() {
this.showFlag = true;
this.selectType = 0;
this.onlyContent = true;
this.$nextTick(() => {
if (!this.scroll) {
this.scroll = new BScroll(this.$refs.food, {
click: true
});
} else {
this.scroll.refresh();
}
});
}
为当前激活的按钮增加一个active的class,通过selectType的值确定当前激活的按钮 <span @click="select(2, $event)" class="block positive" :class="{'active':selectType===2}">{{desc.all}}<span class="count">{{ratings.length}}</span></span>
点击block按钮时,添加select事件改变给父组件food发送一个事件。
select(type, event) {
if (!event._constructed) {
return;
}
this.$emit('select', type);
}
在父组件中接收这个事件,并且改变selectType的值(prop
是单向数据流的,原则上子组件修改props是不被允许,所以我们通过发送事件给父组件,在父组件中改变数值)
<ratingselect @select="selectRating" @toggle="toggleContent" :selectType="selectType" :onlyContent="onlyContent" :desc="desc" :ratings="food.ratings"></ratingselect>
selectRating(type) {
this.selectType = type;
this.$nextTick(() => {
this.scroll.refresh();
});
}
点击toggleContent也是给父组件派发以一个事件,在父组件中修改onlyContent的值
positive和negative的评价的长度通过计算属性positives()和negatives()得到
computed: {
positives() {
return this.ratings.filter((rating) => {
return rating.rateType === POSITIVE;
});
},
negatives() {
return this.ratings.filter((rating) => {
return rating.rateType === NEGATIVE;
});
}
}
接着在food组件写评价内容,根据评论的类型显示点赞和踩的标志,通过给<span>:class一个对象来实现<span :class="{'icon-thumb_up':rating.rateType===0, 'icon-thumb_down':rating.rateType===1}"></span>
评论的显示控制用v-show="needShow(rating.rateType,rating.text)"来实现,v-show可以绑定对象,属性,字段也可以绑定函数的返回值。
v-show="needShow(rating.rateType,rating.text)" class="rating-item border-1px" v-for="rating in food.ratings">
needShow (type, text) {
if (this.onlyContent && !text) {
return false;
}
if (this.selectType === ALL) {
return true;
} else {
return type === this.selectType;
}
}
要对时间的格式进行处理,在rating.rateTime后面加一个filter,在该组件中定义filters。用一个js模块实现formatDate,在src/js文件夹下创建date.js
<div class="time">{{rating.rateTime | formatDate}}</div>
filters: {
formatDate(time) {
let date = new Date(time);
return formatDate(date, 'yyyy-MM-dd hh:mm');
}
}
时间的格式化主要通过正则表达式来实现
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);
}