160 lines
3.0 KiB
Vue
160 lines
3.0 KiB
Vue
<template>
|
|
<view class="star-rate">
|
|
<view
|
|
v-for="(item, index) in maxValue"
|
|
:key="index"
|
|
class="star-wrapper"
|
|
@click="handleClick(index + 1)"
|
|
>
|
|
<text class="star star-bg">☆</text>
|
|
<view class="star-fill" :style="getStarFillStyle(index + 1)">
|
|
<text class="star star-active">★</text>
|
|
</view>
|
|
</view>
|
|
<text v-if="showText" class="score-text">{{ rating.toFixed(1) }}</text>
|
|
<!-- 调试信息 -->
|
|
<view class="debug-info">
|
|
<text>Rating: {{ rating }} / {{ maxValue }}</text>
|
|
</view>
|
|
</view>
|
|
</template>
|
|
|
|
<script>
|
|
export default {
|
|
name: 'StarRate',
|
|
props: {
|
|
value: {
|
|
type: [Number, String],
|
|
default: 0
|
|
},
|
|
max: {
|
|
type: [Number, String],
|
|
default: 5
|
|
},
|
|
allowHalf: {
|
|
type: Boolean,
|
|
default: true
|
|
},
|
|
disabled: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
readonly: {
|
|
type: Boolean,
|
|
default: true
|
|
},
|
|
showText: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
size: {
|
|
type: [Number, String],
|
|
default: 24
|
|
},
|
|
color: {
|
|
type: String,
|
|
default: '#FFD700'
|
|
},
|
|
disabledColor: {
|
|
type: String,
|
|
default: '#C0C4CC'
|
|
},
|
|
void: {
|
|
type: String,
|
|
default: '#C0C4CC'
|
|
}
|
|
},
|
|
computed: {
|
|
rating() {
|
|
let val = parseFloat(this.value) || 0
|
|
if (val > this.maxValue) val = this.maxValue
|
|
if (val < 0) val = 0
|
|
return val
|
|
},
|
|
maxValue() {
|
|
return parseInt(this.max) || 5
|
|
}
|
|
},
|
|
methods: {
|
|
getStarFillStyle(position) {
|
|
const rating = this.rating
|
|
let percentage = 0
|
|
|
|
if (rating >= position) {
|
|
// 当前星星应该完全点亮
|
|
percentage = 100
|
|
} else if (rating > position - 1) {
|
|
// 当前星星需要部分点亮(半星效果)
|
|
percentage = (rating - (position - 1)) * 100
|
|
} else {
|
|
// 当前星星不应该点亮
|
|
percentage = 0
|
|
}
|
|
|
|
return {
|
|
width: percentage + '%'
|
|
}
|
|
},
|
|
handleClick(score) {
|
|
if (this.readonly || this.disabled) return
|
|
|
|
let newScore = score
|
|
if (this.allowHalf && this.rating === score) {
|
|
newScore = score - 0.5
|
|
}
|
|
|
|
this.$emit('input', newScore)
|
|
this.$emit('change', newScore)
|
|
}
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<style lang="less" scoped>
|
|
.star-rate {
|
|
display: flex;
|
|
align-items: center;
|
|
|
|
.star-wrapper {
|
|
position: relative;
|
|
margin-right: 4rpx;
|
|
display: inline-block;
|
|
|
|
.star {
|
|
font-size: 24rpx;
|
|
display: inline-block;
|
|
line-height: 1;
|
|
}
|
|
|
|
.star-bg {
|
|
color: #C0C4CC;
|
|
}
|
|
|
|
.star-fill {
|
|
position: absolute;
|
|
top: 0;
|
|
left: 0;
|
|
overflow: hidden;
|
|
|
|
.star-active {
|
|
color: #FFD700;
|
|
}
|
|
}
|
|
|
|
&:last-child {
|
|
margin-right: 0;
|
|
}
|
|
}
|
|
|
|
.score-text {
|
|
font-size: 20rpx;
|
|
color: #333;
|
|
margin-left: 10rpx;
|
|
}
|
|
|
|
.debug-info {
|
|
margin-top: 10rpx;
|
|
font-size: 18rpx;
|
|
color: #666;
|
|
}
|
|
}</style> |