何时使用 对评价进行展示
一 需求明确
实现一个star组件, 展示5个星, 支持 (全星, 半星, 空星), 支持 大小(24px, 36px, 48px)
一 问题分析
要展示5颗星,v-for
接口定义
属性 | 默认值 | 备注 |
---|
size | 48(备选项,48,36,24) | 星星的大小 (单位px) | score | Number | 星星个数, 为3.6展示3星半 |
图片定义
.star24_half .star36_half .star48_half
状态定义 .on 全星 .half 半星 .off 0星
二. 代码实现
<div class="star" :class="starType">
<span v-for="(itemClass,index) in itemClasses" :class="itemClass" class="star-item" :key="index"></span>
</div>
通过监听 starType 的样式, 控制星的大小
props: {
size:{
type:Number
},
score:{
type:Number
}
},
starType() {
return 'star-' + this.size;
},
.star
.star-item
&.star-48
&.star-36
&.star-24
<template>
<!-- 定义基础默认的样式, :class= 定义动态附加样式 -->
<div class="star" :class="startType">
<span v-for="(itemClass, index) in itemClasses" :class="itemClass" class="star-item" :key="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
}
},
data() {
return {
detailShow: false
}
},
computed: {
startType() {
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="less" scoped>
.bg-image-base(@url: '') {
@2xImgUrl: "@2x.png";
background-image: url("@{url}@{2xImgUrl}");
}
;
@media (-webkit-min-device-pixel-ratio: 2),
(min-device-pixel-ratio: 2) {
.bg-image-base(@url: '') {
@3xImgUrl: "@3x.png";
background-image: url("@{url}@{3xImgUrl}");
}
}
.star {
font-size: 0;
.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-base('star48_on')
}
&.half {
.bg-image-base('star48_half')
}
&.off {
.bg-image-base('star48_off')
}
}
}
&.star-36 {
.star-item {
width: 15px;
height: 15px;
margin-right: 6px;
background-size: 15px 15px;
&:last-child {
margin-right: 0;
}
&.on {
.bg-image-base('star36_on')
}
&.half {
.bg-image-base('star36_half')
}
&.off {
.bg-image-base('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-base('star24_on')
}
&.half {
.bg-image-base('star24_half')
}
&.off {
.bg-image-base('star24_off')
}
}
}
}
</style>
三.调用
<v-star :size="48" :score="3.6"/>
- 注册组件
export default {
...
props: {
},
components: {
'v-star': Star
},
data() {
return {
}
},
created() {// 转换为对应的样式
},
methods: {
}
}
- 引用组件
<v-star :size="48" :score="3.6"/>
- 包裹组件, 决定组件展示的位置, 不去将样式封装在组件内部
<div class="star-wrapper">
<v-star :size="48" :score="seller.score"/>
</div>
.star-wrapper{
text-align: center;
margin-top: 18px;
padding: 2px 0;
}
总结
这里的核心思路在于, 通过运用计算属性computed,
-
利用父级传来的score, 计算出 列表 itemClasses, 补足星数 -
利用父级传来的size, 同步 startType(), 方法, 与 ‘star-’(star-48, star-36, star-24), 样式属性进行配合, 决定了星星的大小 -
.start-item,样式, 与具体的 ‘star-’(star-48, &.on/ &.off) ,样式追加, 先行设计盒子的宽度, 后置入对应的图片, 进行展示 -
使用mixins, 方法, 简化了代码编写的思路 -
将样式容器封装在组件外部, 不影响组件内部的布局
vue 小总结
vue 中, 属性值如果需要用数字 , 需要使用v-bind (简写为: )绑定属性值, ps: 否则, 将被解析为string 字符串, 如下:
<v-star :size="48" :score="3.6"/>
参考文档
https://ant.design/components/rate-cn/
https://element.eleme.cn/#/zh-CN/component/rate
https://github.com/ElemeFE/element/blob/dev/packages/rate/src/main.vue
|