需求分析####
1.星级评价在店铺中多次使用,因此作为组件进行编写
2.星级评价的标准是该店铺的得分,样式以星星的尺寸来划分总共有三种,分别是48,36和24
3.调用插件时传入两个参数,第一个星星的size,数据类型为number,第二个店铺的评分score,数据类型为number
<template>
<div class="star" :class="starType">
<span v-for="itemClass in itemClasses" :class="itemClass" class="star-item" track-by="$index"></span>
</div>
</template>
<script type="text/ecmascript-6">
const LENGTH = 5;
const CLS_ON = 'on';
const CLS_HALF = 'half';
const CLS_OFF = 'off';
export default {
props: {
size: {
type: Number
},
score: {
type: Number
}
},
computed: {
starType() {
return 'star-' + this.size;
},
itemClasses() {
let result = [];
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>
<style lang="stylus" rel="stylesheet/stylus">
@import "../../common/stylus/mixin";
.star
.star-item
display: inline-block
background-repeat: no-repeat
&.star-48
.star-item
width: 20px
height: 20px
margin-right: 22px
background-size: 20px 20px
&:last-child
margin-right: 0
&.on
bg-image('star48_on')
&.half
bg-image('star48_half')
&.off
bg-image('star48_off')
&.star-36
.star-item
width: 15px
height: 15px
margin-right: 16px
background-size: 15px 15px
&:last-child
margin-right: 0
&.on
bg-image('star36_on')
&.half
bg-image('star36_half')
&.off
bg-image('star36_off')
&.star-24
.star-item
width: 10px
height: 10px
margin-right: 3px
background-size: 10px 10px
&:last-child
margin-right: 0
&.on
bg-image('star24_on')
&.half
bg-image('star24_half')
&.off
bg-image('star24_off')
</style>
以上为star组件
其中类名为star的div是存放星星的容器,使用vue的v-for方法对span进行循环,每一个span代表一个星星,星星有三种状态,空白,半星和全星
第1行 <template>中包含组件的html框架
第2行 :class="starType"是v-bind:class的简写,是vue中给元素绑定一个类的方法,其中starType是一个方法该方法在第21行中有声明,返回的是一个字符串,该字符串由'star-' + this.size拼接而成,this.size是调用组件时传入的num,上面有提到num有三种分别是48,36和24,因此完成拼接后,会出现三个类名,分别是star-48,star-36,star-24,这三个类名决定了星星的大小,类名的定义在代码的50行,后面分析
第3行 <span v-for="itemClass in itemClasses" :class="itemClass" class="star-item" track-by="$index"></span>其中v-for是vue的循环写法,由此可见itemClasses()方法返回是一个数组,v-for是对数组的遍历,对于itemClass的声明在代码的第25行,:class="itemClass"从数组中拿到的itemClass以类名的形式绑定到span上用于决定每个span呈现的状态,状态可分为空白,半星和全星三种。track-by="$index"是为了给 Vue 一个提示,以便它能跟踪每个节点的身份,从而重用和重新排序现有元素。
第13行 使用props进行数据传递,之前提到调用该组件时需要传入两个参数,size和score,外部组件调用该组件时,参数的作用域不同star组件无法直接使用size和score参数,因此需要使用props来进行数据传递,使得外部传入的数据可以被正常使用。
第14行 声明size参数
第15行 定义size的参数为number类型,十七行和十八行功能同上
第21行 computed是vue中实时计算使用方法,当vue检测到数据发生变动时就会执行对相应数据有引用的函数
第22行 starType()获取到传入的size返回字符串star-48,star-36或者是star-24作为类名,来决定星星的大小
第25行 itemClasses()方法,主要作用是用于输出星星的状态,根据传入的score即店铺的分数来决定星星的展示,星星总共三种状态,空白,半星和全星,分数则是采用特殊的计算方法映射到星星的状态上,比如店铺分数是4.8分,显示4星半,分数为4.2分,显示为4星,分数为5分,显示为5星。
第26行 let result = [],定义了一个数组,该数组用于存放星星的类名,由于满分为5分,因此该数组的长度应该为5
第27行 let score = Math.floor(this.score×2) / 2,将分数乘以二并向下取整之后除以二,得到x.0或者是x.5的数字
第28行 let hasDecimal = score % 1 !== 0,hasDecimal的值是true或者false对score取余,有余数时hasDecimal为true,无余数时返回false
第29行 let integer = Math.floor(score),对score再次向下取整,此时的score是第二十七行处理后的score
第30行 for循环,根据integer的数值确定向result数组中push类名CLS_ON的个数,由此可以得到全星的个数
ps:LENGTH,CLS_ON,CLS_HALF,CLS_OFF为7~10行定义的常量,分别表示数组的总长度,和星星三种状态的类名
第33行 if语句hasDecimal为true则有半星,false则无半星
第36行 while语句全星循环的半星判断执行完之后对result数组的长度进行判断,小于总长度则向数组中push空白星
第39行 返回result数组。