前言
在数字化产品和服务日益普及的今天,用户体验成为决定应用成败的关键因素之一。而评分系统作为衡量用户满意度和反馈的重要工具,其设计与实现也变得尤为重要。本篇文章将带领你一步步构建一个既美观又实用的评分组件,该组件不仅能够在页面上优雅地展示评分,还能根据用户的操作实时响应,提供个性化的视觉反馈。
正文
对于评分这一个组件,首先让我们思考一下,实现这个组件我们需要实现什么功能。
- 页面可以显示我们要的效果
- 对于评分主题颜色定制
- 实现打分机制
- mouserover鼠标移入事件,mouserout鼠标移出事件,click点击事件
现在我们我们就对这四个功能一一实现
1.显示数据
使用npm快速创建一个Vue项目,父组件App.vue,子组件Rate.vue,把子组件引入父组件中,作为一个标签使用,在父组件中负责将数据传给子组件,子组件拿到数据后,在页面上展示出父组件的要求效果。
App.vue
<template>
<div>
<!-- 不写冒号,则会表示字符3 -->
<Rate
:score="3"
/>
</div>
</template>
<script setup>
// 显示打分
import Rate from './components/Rate.vue'
</script>
<style lang="css" scoped>
</style>
Rate.vue
<template>
<div>
{{rate}}
</div>
</template>
<script setup>
import {defineProps,computed,defineEmits,ref} from 'vue'
let props = defineProps({
score:{
type:Number,
default:0
}
})
let rate = computed(()=>"★★★★★☆☆☆☆☆".slice(5-props.score,10-props.score))
</script>
<style lang="css" scoped>
</style>
这里我们星星展示,是依靠JS中的slice()对字符串进行剪切会获取到我们需要的的长度。
这样就实现了基础的数据显示。
2.定制主题
给星星添加主题颜色,也就是给它添加一个css样式就可以实现了,到那时主题的颜色是我们再父组件中传递的,所以我们再<Rate/>标签中添加主题theme就好了,在defineProps中添加
theme:{
type:String,
default:'blue'
}
默认颜色设置为蓝色。
我们给div通过v-bind动态绑定变量style里面的数据是css属性样式
// 主题可定制性 配置项
const themeObj = {
'black':'#000',
'yellow':'#fadb14',
'blue':'#40a9ff',
'green':'73d13d'
}
const fontStyle = computed(()=>{
return `color:${themeObj[props.theme]};`
})
然后再写一个颜色的配置型,这个配置项大家可以自定义颜色。
3.实现打分以及鼠标事件
我们在页面上打分时,可以发现星星是可以点击的,但是我们这里的星星是字符串形式,无法点击。这里我们将两种不同的星星放在两个的span中让他们两个重叠在一起,这样我们就只显示5个星星了。
在父组件中我们需要实现数据的更新机制,这里我们可以采用事件订阅,将函数updata传给子组件
App.vue
<template>
<div>
<!-- 不写冒号,则会表示字符3 -->
<Rate
@update-score="updata"
:score="score" theme="yellow"
/>
</div>
</template>
<script setup>
// 显示打分
import Rate from './components/Rate.vue'
import {ref} from 'vue'
let score = ref(3)
function updata(num){
score.value = num
}
</script>
<style lang="css" scoped>
</style>
在子组件中,我们定义一个私有化数据width用于保存更新后的数据。在父组件中我们订阅事件update,在子组件中我们声明事件update-score,并创建函数onRate,用于更新数据
//事件
const emits = defineEmits(['update-score'])
// 更新数据
const onRate = (num)=>{
emits('update-score',num)
}
这里的参数num会通过事件订阅机制将其传给父组件中的函数
function updata(num){
score.value = num
}
这里的星星亮几颗,我们用一个相对单位em完成,我们给实心的星星动态绑定style,我们这里用width宽度来实现有几颗星,是因为我们空心的星星和实心的星星重叠了,只需要保证实心的星星按照打分实现就好了,不需要处理空心。
const fontWidth = computed(()=> `width:${width.value}em;`)
对于鼠标事件,我们需要能够点击星星,我们使用v-for将其遍历在span标签中,而不是使用字符串,这样我们就可以点击了。然后我们给span标签绑定事件mouseOver,mouseOut,以及点击事件,点击事件我们就绑定onRate,mouseOver当鼠标移入触时,星星要亮起来,就需要将数据传入更新,鼠标移出时,就恢复原来的状态。
Rate.vue
<template>
<div :style="fontStyle">
<div class="rate" @mouseout="mouseOut">
<span class="rate star" @mouseover = "mouseOver(num)" v-for="num in 5" :key="num">☆</span>
<span class="hollow" :style="fontWidth">
<span v-for="num in 5" :key="num" class="star" @mouseover = "mouseOver(num)" @click="onRate(num)">★</span>
</span>
</div>
</div>
</template>
<script setup>
import {defineProps,computed,defineEmits,ref} from 'vue'
let props = defineProps({
score:{
type:Number,
default:0
},
theme:{
type:String,
default:'blue'
}
})
// 主题可定制性 配置项
const themeObj = {
'black':'#000',
'yellow':'#fadb14',
'blue':'#40a9ff',
'green':'73d13d'
}
let rate = computed(()=>"★★★★★☆☆☆☆☆".slice(5-props.score,10-props.score))
const fontStyle = computed(()=>{
return `color:${themeObj[props.theme]};`
})
// 私有状态 mouseover mouseout 改变状态
let width = ref(props.score)
//事件
const emits = defineEmits(['update-score'])
// 更新数据
const onRate = (num)=>{
emits('update-score',num)
}
const fontWidth = computed(()=> `width:${width.value}em;`)
const mouseOver = (num)=>{
width.value = num
}
const mouseOut = ()=>{
width.value = props.score
}
</script>
<style lang="css" scoped>
.star{
letter-spacing: 2px;
}
.rate{
position: relative;
display: inline-block;
}
.rate > span.hollow{
position: absolute;
display: inline-block;
top: 0;
left: 0;
overflow: hidden;
}
</style>
感谢大家阅读,若有不足,恳请各位指出!!!