vue3实现星星打分组件
1、整颗星全打
<template>
<div class="star-rating">
<span
v-for="index in 5"
:key="index"
class="star"
:class="{ active: index <= (hoverIndex || rating) }"
@click="setRating(index)"
@mousemove="hoverIndex = index"
@mouseleave="hoverIndex = null"
>
★
</span>
</div>
</template>
<script setup>
import { ref } from "vue";
const rating = ref(0); // 当前评分值(0-5)
const hoverIndex = ref(null); // 鼠标悬停时的星星索引
// 设置评分值
const setRating = (index) => {
rating.value = index;
console.log("rating set:", index, "hoverIndex:", hoverIndex.value);
};
// 观测下两个值的变化
watch([rating, hoverIndex], ([newRating, newHoverIndex]) => {
console.log("new rating:", newRating, "new hoverIndex:", newHoverIndex);
});
</script>
<style scoped>
.star-rating {
display: inline-flex;
font-size: 24px;
color: #ccc;
}
.star {
cursor: pointer;
margin: 0 2px;
transition: color 0.2s;
}
.star.active {
color: gold;
}
.star:hover {
color: gold;
}
</style>
2、可以打半颗星
<template>
<div class="star-rating">
<span
v-for="index in 5"
:key="index"
class="star-container"
@click="setRating($event,index)"
@mousemove="handleHover($event,index)"
@mouseleave="hoverRating = null"
>
<span class="star-background">★</span>
<span
class="star-foreground"
:style="getStarStyle(index)"
>★</span>
</span>
</div>
</template>
<script setup>
import { ref, computed } from 'vue';
const rating = ref(0); // 当前评分值(0-10)
const hoverRating = ref(null); // 鼠标悬停时的评分值
// 设置评分
const setRating = (event,index) => {
const clickX = event.offsetX; // 获取点击位置相对于星星的横坐标
const starWidth = event.target.offsetWidth; // 获取星星的宽度
const isHalf = clickX < starWidth / 2; // 判断是否点击了左半边
rating.value = (index - 1) * 2 + (isHalf ? 1 : 2); // 计算评分值
};
// 处理鼠标悬停
const handleHover = (event,index) => {
const hoverX = event.offsetX; // 获取悬停位置相对于星星的横坐标
const starWidth = event.target.offsetWidth; // 获取星星的宽度
const isHalf = hoverX < starWidth / 2; // 判断是否悬停在左半边
hoverRating.value = (index - 1) * 2 + (isHalf ? 1 : 2); // 计算悬停评分值
};
// 获取星星前景的样式
const getStarStyle = (index) => {
const currentRating = hoverRating.value || rating.value; // 当前显示的评分值
const starValue = (index - 1) * 2; // 当前星星的起始分值
let width = '0%';
if (currentRating >= starValue + 2) {
width = '100%'; // 整颗星
} else if (currentRating >= starValue + 1) {
width = '50%'; // 半颗星
}
return { width };
};
// 观测下两个值的变化
watch([rating, hoverRating], ([newRating, newHoverRating]) => {
console.log("half new rating:", newRating, "new hoverRating:", newHoverRating);
});
</script>
<style scoped>
.star-rating {
display: inline-flex;
font-size: 24px;
color: #ccc;
}
.star-container {
position: relative;
cursor: pointer;
margin: 0 2px;
}
.star-background,
.star-foreground {
display: inline-block;
font-size: inherit;
}
.star-background {
color: #ccc; /* 未选中的星星颜色 */
}
.star-foreground {
position: absolute;
top: 0;
left: 0;
color: gold; /* 选中的星星颜色 */
overflow: hidden;
white-space: nowrap;
}
</style>
css部分解析:
1. .star-rating
-
display: inline-flex;
:-
将容器设置为弹性盒子布局,使星星水平排列。
-
-
font-size: 24px;
:-
设置星星的大小为 24px。
-
-
color: #ccc;
:-
设置默认的星星颜色为灰色(未选中状态)。
-
2. .star-container
-
position: relative;
:-
设置相对定位,为子元素(
.star-foreground
)的绝对定位提供参考。
-
-
cursor: pointer;
:-
将鼠标指针设置为手型,表示星星是可点击的。
-
-
margin: 0 2px;
:-
设置星星之间的间距为 2px。
-
3. .star-background
和 .star-foreground
这两层 span
用于实现半星效果:
-
.star-background
:-
显示未选中的星星(灰色)。
-
color: #ccc;
:-
设置背景星星的颜色为灰色。
-
-
-
.star-foreground
:-
显示选中的星星(金色)。
-
position: absolute;
:-
设置为绝对定位,覆盖在
.star-background
之上。
-
-
top: 0; left: 0;
:-
将前景星星定位到容器的左上角。
-
-
color: gold;
:-
设置前景星星的颜色为金色。
-
-
overflow: hidden;
:-
隐藏超出容器范围的内容,用于实现半星效果。
-
-
white-space: nowrap;
:-
防止文本换行,确保星星显示为单行。
-
-
半星效果是通过控制 .star-foreground
的宽度来实现的:
-
如果星星是半星,设置
.star-foreground
的宽度为50%
,只显示左半边。 -
如果星星是整星,设置
.star-foreground
的宽度为100%
,显示完整的星星。