五星评分的效果是怎么实现的
前言
如今外卖平台、电商平台乃至日常的生活中,五星评价已经成为用户反馈产品和服务质量的常用方式。这种评分方式不仅能让用户快速给出评价,同时也让其他用户可以更直观地感受到产品的受欢迎程度,这篇文章我将带你实现一个五星评价的小demo。
技术栈
- HTML:展示星星图标
- CSS:样式
- JS与vue:实现页面动态交互与数据传输
实现过程
功能:
在鼠标移到第几颗星星上时就亮几颗星星,点击后便保持这个状态,只是单纯移开就恢复上一次的星星数量。
原理:
让实星覆盖空星,即用★把☆盖住。
文件结构:
App.vue:
概述:
在script中定义响应式的score(星星的数量),update方法(用于更新星星的数量),然后将它们两个传给Rate1.vue,我们要遵循组件间通信的原则,数据状态及修改归父组件管理。
Rate1.vue:
<template>
<div :style="fontStyle">
<div class="rate" @mouseout="mouseOut">
<span @mouseover="mouseOver(num)"
v-for="num in 5"
:key="num">☆</span>
<span class="hollow" :style="fontwidth">
<span v-for="num in 5"
:key="num" @click="onRate(num)"
@mouseover="mouseOver(num)">★</span>
</span>
</div>
</div>
</template>
<script setup>
import { defineProps, computed, defineEmits,ref } from 'vue'
// 组件自身的状态
let fontwidth = computed(() => `width:${width.value}em;`)
let props = defineProps({
value: Number,
theme: { type: String, default: 'orange' }
})
let width = ref(props.value)
let themeObj = {
orange: '#fa541c',
blue: '#40a9ff',
green: '#73d13d',
black: '#000',
red: '#f5222d',
yellow: '#ffaa00'
}
const fontStyle = computed(() => {
return `color:${themeObj[props.theme]}`
})
let emits = defineEmits(["update-rate"])
const onRate = (num) => {
emits("update-rate", num)
}
function mouseOver(i){ // 鼠标移到上面时动态改变星星数量
width.value = i;
}
function mouseOut(){ // 鼠标移开时将星星保持先前的数量
width.value = props.value
}
</script>
<style lang="css" scoped>
.rate{
position: relative;
display: inline-block;
}
.rate span {
/* letter-spacing: 3px; */
width:1em;
display: inline-block;
}
.rate > span.hollow{
position: absolute;
display: inline-block;
top:0;
left:0;
width: 0;
height: 22px;
overflow: hidden; // 超出部分隐藏
}
</style>
举个例子:
为了让大家思路更加清晰,我们先把第65行这段十分重要的代码overflow: hidden
注释,看看效果:
当我们选择三颗星时,有两颗会出现在下面。
实现思路:
将空星星和实星定位在同一位置上,通过鼠标的操作更改实星星容器的宽度,让多余的星星被挤到下一行,然后给定只能放一行星星的容器高度,利用overflow: hidden
将多余的星星隐藏。
为什么要用到defineEmits
,而不是直接将update方法写到Rate1.vue中:
因为子组件与父组件之间的通信主要依赖于“props down, events up”的原则。这意味着子组件可以接收来自父组件的数据(通过 props),但不能直接修改这些数据。如果子组件需要改变父组件的状态,它应该通过触发自定义事件(使用 emits
选项)来通知父组件,然后由父组件决定是否以及如何改变其状态。
拓展:
细心的掘友会发现到其中有个themeObj
包含着不同的颜色主题,它的作用就是让这个demo更好地复用,定义好多个主题,就比如某团代表黄色,饿了么代表蓝色,我们可以根据不同的开发要求来更换主题。
效果:
五星好评:
一般,我只能给到两星:
结语
这样我们就完成了一个五星评价的小demo,当然也有很多不同的实现方法,期待大家的分享。如果对代码哪里有疑问的话可以在评论区提出来,我都会进行解答。
转载自:https://juejin.cn/post/7389651543719166004