前言
在数字化时代,评分系统已成为各类在线平台不可或缺的一部分,从外卖应用的美食评价,到影视平台的观影打分,再到电子商务的商品评级,星级评分不仅加深了用户与产品的互动,还为商家提供了宝贵的用户反馈,促进了产品和服务的持续优化。今天,我们就开始学习亲手打造一个能够实现星级评分的小组件。
正文
分析需求
我们想要实现是动态效果样式为:
为了实现组件的功能,我们需要实现的需求具体如下:
-
分数的动态显示:
- 当用户将鼠标悬停在星星上时,应即时显示当前悬停的星星及其以下所有星星的高亮状态,以直观反映可能的评分。
- 用户完成评分后,应清晰展示最终评分结果。
-
主题定制功能:
- 系统应提供可配置的主题选项,包括但不限于星星的颜色、大小、形状及背景样式,以适应不同的网站设计风格。
-
鼠标悬停(mouseover)事件处理:
- 当鼠标悬停在某颗星星上时,应触发事件,以提示用户当前的潜在评分值。
-
鼠标离开(mouseout)事件处理:
- 当鼠标离开星星区域时,应恢复到之前的状态,除非已经完成了评分。
-
点击(click)事件响应:
- 用户点击星星时,应记录并提交用户的评分选择,反映最新的评分状态。
了解了需求后我们开始第一步,创建vue项目==>
创建项目
- 在集成终端上运行下列代码创建一个vue项目
npm init vite
- 选择Vue和JavaScript,命名这里取的是rate
在vue的文件夹下运行完成后
- 在终端里输入
cd rate
- 来到vue里刚刚创建的rate目录下输入下行命名添加依赖
npm i
- 添加Rate.vue和App.vue文件
项目目录:
此时项目框架就已经配置好了
定制组件
Rate.vue
<template>部分:
- 在
div内部,有一个带有两个span元素的ratediv:一个用于未评级的部分(☆),另一个用于已评级的部分(★)。
该组件通过鼠标悬停和点击事件来更新评级。
当用户将鼠标悬停在某个星星上时,会高亮显示从第一个星到该星的所有星星。
当鼠标移出时,高亮显示会回到当前的评分值。
点击星星时,组件会发出一个update-score事件,将新的评分值传递给父组件。
<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>
<script setup>设置部分:
- 定义
score和theme属性,分别用于接收初始评分和主题颜色。 - 使用计算属性
fontStyle来根据主题颜色动态设置文本颜色。 rate计算属性用于生成表示当前评分的字符串fontWidth计算属性用于设置已评级星星的宽度,使其与当前评分值相匹配(这里实际上会有差别,因为'★'和'☆'的宽度有略微不同)。
空心☆:
实心★:
width引用用于存储鼠标悬停或点击时的临时评分值。onRate函数用于处理点击事件,触发update-score事件以通知父组件更新评分。mouseOver和mouseOut函数分别处理鼠标悬停和移出事件,更新width值以反映当前状态。
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);
//通知父组件更新评分
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
}
<style>部分:
.star:设置星星之间的间距。.rate:定位和显示整个评分组件。.hollow:绝对定位已评级星星的部分,确保它们覆盖在未评级星星之上,同时限制其宽度以正确显示评分。
.star {
letter-spacing: 3px;
}
.rate {
position: relative;
display: inline-block;
}
.rate>span.hollow {
position: absolute;
display: inline-block;
top: 0;
left: 0;
overflow: hidden;
}
分数的显示
App.vue:
<script setup>部分:
//显示打分
import Rate from './components/Rate.vue'
import { ref } from 'vue'
let score = ref(3)//定义初始评分为3
function update(num) {
score.value = num
}
- 导入组件:首先,从当前目录下的
components文件夹中导入Rate组件。 - 使用
ref创建响应式数据:通过import { ref } from 'vue'导入了ref函数,用于创建一个响应式的score数据,初始值为3。 - 定义
update函数:这个函数接收一个参数num,用于更新score的值。它将接收到的数值赋给了score.value,这是因为ref创建的数据是一个引用类型,需要通过.value来访问或修改其实质内容。
完整代码:
<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: {
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);
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>
.star {
letter-spacing: 3px;
}
.rate {
position: relative;
display: inline-block;
}
.rate>span.hollow {
position: absolute;
display: inline-block;
top: 0;
left: 0;
overflow: hidden;
}
</style>
定制主题
可以根据需求自定义评分的颜色样式
<template> 部分:
<div>
<Rate @update-score="update" :score="score" theme="black" />
<Rate @update-score="update" :score="score" theme="yellow" />
<Rate @update-score="update" :score="score" theme="blue" />
<Rate @update-score="update" :score="score" theme="green" />
</div>
这部分用来定义组件的模板结构。
- 使用
Rate组件:在模板中,Rate组件被使用,传入了score和theme属性,以及一个@update-score事件处理器,该处理器会在Rate组件触发update-score事件时调用update函数。
完整代码:
<script setup>
//显示打分
import Rate from './components/Rate.vue'
import { ref } from 'vue'
let score = ref(3)//定义初始评分为3
function update(num) {
score.value = num
}
</script>
<template>
<div>
<Rate @update-score="update" :score="score" theme="black" />
<Rate @update-score="update" :score="score" theme="yellow" />
<Rate @update-score="update" :score="score" theme="blue" />
<Rate @update-score="update" :score="score" theme="green" />
</div>
</template>
<style scoped></style>
结语
以上就是本文的全部内容,评分组件使用广泛,希望本文对你的项目开发与对组件的掌握有所帮助,感谢你的阅读!