用vue写一个组件库的必备组件:星级评分系统
前言
在许多应用中,用户评分功能是非常常见的需求之一。一个好的评分组件不仅需要实现基本的功能,还应该具备良好的用户体验和高度的可定制性。本文将介绍如何使用Vue
构建一个动态、可定制主题的评分组件,来扩充我们的组件库。
实现效果如下:
正文
组件设计
我们的评分组件可以实现的功能:
- 用户可以通过点击星星来给内容打分。
- 当鼠标悬停在星星上时,半选中的星星会显示完整状态。
- 当鼠标离开后,星星���态固定。
- 用户可以自定义评分的主题颜色。
准备工作
准备两个文件:在
src
下的App.vue
和在src
下components
文件夹下的Rate.vue
。
开始操作
当前页面:App.vue
开始动手操作,首先,我们从父组件开始,它包含了评分组件以及更新评分逻辑,我们来到App.vue
。
<template>
<div>
<Rate @update-score="update" :score="score" theme="yellow"></Rate>
</div>
</template>
<script setup>
import Rate from './components/Rate.vue'
import { ref } from 'vue'
// 初始评分为 3 星
let score = ref(3)
function update(num) {
score.value = num
}
</script>
<style lang="scss" scoped>
/* 样式可以根据需要添加 */
</style>
解析:
- 首先评分前,我们把星星默认设置为三颗(
let score = ref(3)
),把他声明为响应式数据,用于后面更改星星的个数,:score="score
动态绑定星星的个数,当score
的值发生变化时,Vue会自动更新与之绑定的属性,因此,当score
的值在父组件中发生变化时,子组件也会接收到新的值,并根据新的值更新其显示的评分,这里实现父组件组件向子组件通信,来传递数据。 - 接着
@update-score="update"
,@update-score
是在子组件发布一个事件(下面代码可以看到),我们在父组件里这里订阅,里面传递了子组件给父组件的星星个数,这里实现子组件向父组件通信,来传递数据,我们通过function update(num)
这个函数接受子组件传来的数据,并把星星个数更新掉(这时当鼠标点击评完分后鼠标离开星星,只要不再次点击,就默认为这个个数) - 最后我们可以通过
theme="yellow"
把星星的颜色设置成自己想要的颜色,这里的静态字符串"yellow"
作为值传递给子组件的theme
属性,前面不用带v-bind:
/:
当前页面:Rate.vue
然后我们来到components文件夹下的Rate.vue,这里是实现功能的核心区域。
<template>
<div :style="fontStyle">
<div class="rate" @mouseout="mouseOut">
<span class="star" @mouseover="mouseOver(num)" v-for="num in 5":key="num">☆</span>
<span class="hollow" :style="fontWidth">
<span class="star" @click="onRate(num)" @mouseover="mouseOver(num)" v-for="num in 5":key="num">★</span>
</span>
</div>
</div>
</template>
<script setup>
import {defineProps,computed,defineEmits,ref } from 'vue'
let props = defineProps({
score:{
typeof:Number,
default:0,
},
theme:{
typeof:String,
default:'blue',
}
})
//主题可定制性
const themeObj={
'black': '#000',
'yellow': '#fadb14',
'blue': '#40a9ff',
'green':'#73d13d'
}
const fontStyle=computed(()=>{
return `color:${themeObj[props.theme]};`
})
//私有状态 mouseover mouseout 改变状态
let width=ref(props.score)
let 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: 3px;
cursor: pointer;
}
.rate{
position: relative;
display: inline-block;
}
.rate>span.hollow{
position: absolute;
display: inline-block;
top:0;
left: 0;
overflow: hidden;
}
</style>
解析:
1.首先我们通过let props = defineProps()
接收到从父组件传来的数据:score
和theme
,如果没有传就默认为零颗星星和默认星星为蓝色,:style="fontStyle"
通过父组件传来的颜色设置星星的颜色。
2.接着我们通过v-for="num in 5"
把五颗☆和★放在一行通过top:0和left: 0
;把两组星星重合,这里一直都是五颗☆和★,letter-spacing: 3px;
,设置了每个星星的间隙,:style="fontWidth"
用于把个数转换为宽度,已经设置好了,星星能够完整的覆盖,如果通过循环个数来实现的话,当鼠标来回移动,就不算是mouseover
了就实现不了上面的动画效果了,所以我们才把个数变为宽度,并且通过overflow: hidden;
把多的星星隐藏掉来实现效果。
3.@mouseout="mouseOut"
,@mouseover="mouseOver(num)
,"@click="onRate(num)"
,都是修改星星的个数来修改宽度的,let emits=defineEmits(['update-score'])
发布一个事件,当用户点击后,这个事件携带者数据传给父组件,父组件订阅后就可以获得这个数据来使用了。
总结
通过以上代码,这样我们就可以创建一个功能完备且外观美观的评分组件。此外,该组件支持多种主题颜色,使得它能够适应不同的应用场景。希望这个示例能帮助你理解 Vue中组件的实现细节,并激发你创建更多有趣的应用。感谢你的阅读!可以帮忙点点赞吗,十分感谢!
转载自:https://juejin.cn/post/7399530649999441954