Vue五星评分组件设计与实现:从基础到进阶
根据之前的学习,了解到Vue中的组件化的强大,不仅简洁高效,还可以复用。这代表着,当我们先将每个组件做好,然后将这些组件拼在一起,就像是在拼乐高一样,最后组成一个成品。而且这些组件我们还能用在不同的地方,甚至不同的项目也可以使用同一个组件。比如一些美团和淘宝的评分页面中的五星好评:


那我们是不是也可以做一个专门的五星好评的组件呢,用于以后我们的项目中。试试看吧
star
思路
- 开头就不用多说,创建一个Vue项目命名为star就好,方便以后我们的查找和使用。将里面我们用不上的东西通通删掉,然后呢创建一个组件名为Rate0吧。
- Rate组件中就存放展示星星的逻辑就好了,当有数据传入的时候,就显示几颗星星就行
- 这样的话,我们需要将Rate作为子组件挂载在根组件App上,就可以用了
- 而App中存放我们的数据信息,利用组件间通信的原则,数据状态归父组件管理 ,通过props 传递给子组件
- 而我们的子组件不可以直接修改父组件的数据状态,只需要接受参数,做出响应就行。
Rate0组件
代码片段:
在这里,我们运用vue中提供的defineProps
方法和 computed
属性:
defineProps
是Vue 3中用于定义组件接收的props的��方法。它替代了旧版本Vue中的props
选项,并提供了类型检查和默认值设置等功能。使用defineProps
可以使你的组件更加健壮,因为它确保了传入的props符合预期的类型和格式。例如,在我的Rate
组件中,defineProps
被用来声明value
prop的类型为Number
。如果接收到的值不是数值,就会触发一个警告。computed
属性是Vue中一种高效的方式,用于基于响应式依赖项计算派生数据。当依赖项改变时,computed
属性会自动重新计算其值,而且只有在其相关依赖发生更改时才会重新计算,这可以避免不必要的计算和渲染。例如,这里rate
依赖于props.value
,每当value
更新时,rate
也会自动更新。
这里我们采用字符串切割的方法,使用slice()
方法来动态生成这个字符串。
-
'★★★★★☆☆☆☆☆'
是一个包含固定数量星星的字符串,前五个是“满星”,后五个是“空星”。 -
slice(5 - props.value, 10 - props.value)
这个表达式根据props.value
的大小从原始字符串中截取子串:- 如果
value
是5,则slice(0, 5)
会返回所有的“满星”。 - 如果
value
是1,则slice(4, 9)
会返回一个“满星”后面跟着四个“空星”。
- 如果
这样的话,我们就不是可以根据父组件传递下来的值,进行响应式更新数据了嘛
App根组件
- 我们先将star的数量设置为具体的某个值看看效果。
运行结果:
OK的,相关效果已经实现了,并且还测试了一下,如果传入的不是规定的数值,就会触发警告。
Rate1组件
既然已经实现了,那么我们再来想想看,他们商家的星星好像不是黑色,每家的星星颜色都有点不同吧。呦西,再在父组件中加入一个参数theme
来设置颜色不就好了,之后想要什么颜色就设什么颜色呗
App根组件:
Rate1组件:
运行结果:
好像还可以吧,通过父组件传过来的参数,去修改css样式,以达到改变颜色的效果。
Rate2组件
可是,好像美团和淘宝上的是通过手点的方式来改变的星星的多少。那我们是不是也可以这样做呢。所以我们需要一个可以通过鼠标悬停和点击来动态调整评分组件。OK那就来升级一下
构造一下思路
- 首先,我们需要五个空星和五个实星,将他们放在同一个div容器中,之后需要他们一个个显示,所以就不用上面的方法(把他们放在一个字符串里),用v-for循环输出每个星星,并且每个星星上都有对应的key,方便之后的定位。
- 通过设置该div容器的css样式与实星的css样式为父子元素关系,这样实星就可以相对于div容器来定位,而不会影响其他的元素布局
- 然后就是考虑鼠标悬在星星上时,应该要触发某个方法,来实时改变某个状态,将实星显示出来,覆盖在空星上
- 当鼠标不在星星上的时候,也应该要触发某个方法,让状态恢复到之前的状态或者点击之后的状态,这样就解决了鼠标移入移出时,星星的变化效果
- 那么当我们点击的时候,要触发某个方法去修改星星的数量值,而子组件不可以直接修改父组件的数据状态,需要通过自定义事件传递给父组件,所以要在父组件App中创建一个自定义事件来改变星星的数量值,并且将这个方法传给子组件,然后子组件中设置一个点击事件并且获取到星星的数量值,之后再调用传过来的自定义事件。
App根组件 先在App根组件中,创建好自定义事件,并传给子组件
Rate2组件
-
先按照思路,在
<template>
中将html代码先写入,将各个事件命名好<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 @click="onRate(num)" @mouseover="mouseOver(num)" v-for="num in 5" :key="num">★</span> </span> </div> </div>
-
然后在
<script setup>
中将每个事件都实现一下。import { ref, defineProps, computed, defineEmits } from 'vue'; let props = defineProps({ value: Number, theme: { type: String, default: 'orange'} }) let width = ref(props.value) let fontwidth = computed(() => `width: ${width.value}em;`); let themeObj = { orange: '#fa541c', blue: '#40a9ff', green: '#73d13d', black: '#000', red: '#f5222d', yellow: '#fadb14' } 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; }
通过修改装着实星这个容器的宽度去展示实星的个数。这里要注意从父组件中获取自定义事件的方法
defineEmits
以及使用方法,要传入俩个参数(一个是自定义事件,一个是接受的参数,这里是需要修改的星星个数) -
最后是
<style lang="css" scoped>
的编译,运用position
来定位.rate { position: relative; display: block; } .rate span{ display: inline-block; width: 1rem; height: 22px; overflow: hidden; } .rate > span.hollow { position: absolute; display:block; top:0; left:0; width:0; overflow:hidden; }
运行结果
OK了,这里就将淘宝的五星好评整出来了,以后自己也可以直接用了。
结尾
通过一系列的迭代和优化,我们成功地从零开始构建了一个高度可定制的五星评分组件。从最初的静态展示到动态响应用户交互,再到最终实现鼠标悬停预览与点击评分的功能,我们不仅学习了Vue.js的核心概念,如响应式状态管理、组件通信以及样式定制,还深入了解了如何利用Vue的Composition API来组织和封装组件逻辑。
这一过程展示了Vue.js框架的强大和灵活性,以及组件化开发模式的高效性。无论是对于初学者还是有一定经验的开发者来说,这样的实践都是提升技能和理解Vue架构的绝佳方式。
未来,我们可以轻松地复用这个组件,或者在此基础上进一步扩展,加入更多个性化功能,如半星评分、动画效果等。组件化开发不仅简化了前端开发流程,还提高了代码的重用性和项目的可维护性。
如果你对本文有任何疑问或见解,欢迎留言讨论。期待在前端开发的学习旅程中,与你一起加油!
转载自:https://juejin.cn/post/7389925417786802213