一、效果
![](https://img-blog.csdnimg.cn/direct/7f06a36ccd234d84b790bce7fa63fa4b.gif)
二、代码
子组件stars.vue:
<template>
<div class="stars">
<div class="star" v-for="star in stars" :key="star" @click="setScore(star)">
<svg
t="1719659437525"
class="icon"
viewBox="0 0 1024 1024"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
p-id="2422"
width="30"
height="30"
ref="starRef"
@mousemove="onMousemove(star)"
@mouseleave="onMouseleave"
>
<path
:class="{ highlighted: star <= scoreMove }"
d="M313.991837 914.285714c-20.37551 0-40.228571-6.269388-56.946939-18.808163-30.302041-21.942857-44.930612-58.514286-38.661225-95.085714l24.032654-141.061225c3.134694-18.285714-3.134694-36.571429-16.195919-49.110204L123.297959 509.910204c-26.644898-26.122449-36.04898-64.261224-24.555102-99.787755 11.493878-35.526531 41.795918-61.126531 78.889796-66.35102l141.583674-20.375511c18.285714-2.612245 33.959184-14.106122 41.795918-30.30204l63.216326-128.522449C440.946939 130.612245 474.383673 109.714286 512 109.714286s71.053061 20.897959 87.24898 54.334694L662.987755 292.571429c8.359184 16.195918 24.032653 27.689796 41.795918 30.30204l141.583674 20.375511c37.093878 5.22449 67.395918 30.82449 78.889796 66.35102 11.493878 35.526531 2.089796 73.665306-24.555102 99.787755l-102.4 99.787755c-13.061224 12.538776-19.330612 31.346939-16.195919 49.110204l24.032654 141.061225c6.269388 37.093878-8.359184 73.142857-38.661225 95.085714-30.302041 21.942857-69.485714 24.555102-102.4 7.314286L538.122449 836.440816c-16.195918-8.359184-35.526531-8.359184-51.722449 0l-126.955102 66.87347c-14.628571 7.314286-30.302041 10.971429-45.453061 10.971428z m162.481632-96.653061z"
:fill="star <= score ? 'rgb(240, 224, 17)' : 'rgba(108, 113, 120, 1)'"
p-id="2423"
></path>
</svg>
</div>
</div>
</template>
<script setup lang="ts">
import { computed, ref } from "vue";
const props = defineProps<{
count: number;
}>();
//可选,作为选择后的额外操作
const emit = defineEmits(["update:count"]);
//分数,鼠标移入后的分数
const scoreMove = ref(-1);
//与父组件的数据绑定的分数
const score = defineModel("starsNum", {
type: Number,
default: 0,
});
const stars = computed(() => {
return props.count;
});
const setScore = (index: number) => {
score.value = index;
emit("update:count", index);
};
const onMousemove = (index: number) => {
scoreMove.value = index;
};
const onMouseleave = () => {
scoreMove.value = 0;
};
</script>
<style scoped>
.stars {
display: flex;
justify-content: center;
align-items: center;
}
.star {
width: 30px;
height: 30px;
border-radius: 50%;
}
.highlighted {
fill: rgb(251, 234, 47);
}
.num {
font-size: 20px;
margin-left: 10px;
}
</style>
父组件:
<template>
<div class="page">
<div class="strasBox">
<div class="starDiv">
<starts
:count="count1"
v-model:starsNum="starsNum.count1"
@update:count="setCount1"
></starts
><span>{{ starsNum.count1 }}</span>
</div>
<div class="starDiv">
<starts :count="count1" v-model:starsNum="starsNum.count2"></starts
><span>{{ starsNum.count2 }}</span>
</div>
<div class="starDiv">
<starts :count="count1" v-model:starsNum="starsNum.count3"></starts
><span>{{ starsNum.count3 }}</span>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, reactive } from "vue";
import starts from "../components/stars.vue";
const count1 = ref(5);
let starsNum = reactive({
count1: 0,
count2: 0,
count3: 0,
});
//一键设置三个星星的值
let flag = true;
const setCount1 = (payload: number) => {
if (flag) {
starsNum.count2 = payload;
starsNum.count3 = payload;
flag = false;
}
};
</script>
<style scoped>
.page {
width: 100%;
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
background-color: #ce9f9f;
}
.starDiv {
display: flex;
justify-content: center;
align-items: center;
font-size: 24px;
font-weight: 800;
color: #ffffff;
}
span {
margin-left: 10px;
}
</style>
ht