大厂都在用的定制化组件,赶紧来掌握一下吧!
引言
定制化vue组件是前端工程师的必修课,在这篇文章中,我们将介绍如何使用 Vue 3 定制一个星星打分组件。我们将从最基础的星星打分组件开始,逐步增加功能,最终实现一个具有主题颜色和动态交互功能的复杂组件。我们还将详细讲述 Vue 组件的 props、computed 和父子通信等知识点。
基础星星打分组件
首先,我们来实现一个最基础的星星打分组件,它只显示打分的星星数量,首先在components目录下创建Rate0.vue。
Rate0.vue
<template>
<div>{{ rate }}</div>
</template>
<script setup>
import { defineProps, computed } from 'vue';
let props = defineProps({
value: Number
});
let rate = computed(() => "★★★★★☆☆☆☆☆".slice(5 - props.value, 10 - props.value));
</script>
<style scoped>
</style>
在这个组件中,我们使用了 defineProps
来定义组件的 props,并使用 computed
计算属性来根据传入的 value
生成相应数量的星星。用的slice函数去切割这个实星和空星的字符串,达到显示评分的星星的效果。
App.vue
<script setup>
import HelloWorld from './components/HelloWorld.vue'
import Rate from './components/Rate0.vue';
import {ref} from 'vue';
let score = ref(3)
function update(num) {
score.value = num
}
</script>
<template>
<div>
<Rate :value="3"/>
</div>
</template>
<style scoped>
</style>
具有主题颜色星星打分组件
接下来,我们在基础组件的基础上,添加主题颜色的功能。通过 theme
属性,可以为星星设置不同的颜色。我们创建一个Rate1.vue。
Rate1.vue
<template>
<div :style="fontstyle">{{ rate }}</div>
</template>
<script setup>
import { defineProps, computed } from 'vue';
let props = defineProps({
value: Number,
theme: { type: String, default: 'orange' }
});
const themeObj = {
orange: '#fa541c',
blue: '#40a9ff',
green: '#73d13d',
black: '#000',
red: '#f5222d',
yellow: '#fadb14'
};
let rate = computed(() => "★★★★★☆☆☆☆☆".slice(5 - props.value, 10 - props.value));
const fontstyle = computed(() => `color:${themeObj[props.theme]}`);
</script>
<style scoped>
</style>
在这个组件中,我们引入了 theme
属性,并通过 themeObj
对象存储了不同主题的颜色值。fontstyle
计算属性用于动态生成包含主题颜色的样式。
fontstyle
的实现是通过 computed
计算属性,根据传入的 theme
值,从 themeObj
对象中取出对应的颜色值,并生成一个包含该颜色的样式字符串:
const fontstyle = computed(() => `color:${themeObj[props.theme]}`);
为什么使用 themeObj
对象
使用 themeObj
对象的好处在于可以集中管理颜色值,便于维护和扩展。假如我们以后想添加新的主题颜色,只需要在 themeObj
中添加相应的键值对即可,而不需要修改其他代码。
效果如下图:
动态交互星星打分组件
在这个部分,我们将实现一个动态交互的星星打分组件,用户可以通过鼠标悬停和点击来选择打分。
实现原理
将实心星星放在空心星星上:通过 CSS 定位,把实心星星叠加在空心星星上。
通过鼠标悬停和点击设置实心星星的宽度:鼠标悬停时,设置实心星星的宽度来显示悬停的效果;点击时,通过自定义事件将打分结果传递给父组件,更新实心星星的宽度,超出宽度的实心星星被隐藏从而达到悬停或点击星星就有几颗实心星星的效果。
首先我们定义了 value
和 theme
两个 props,value
表示初始的打分值,theme
表示星星的主题颜色。width
是一个响应式的变量,初始值为 props.value
,用于控制实心星星的宽度。fontwidth
是一个计算属性,根据 width
的值生成相应的宽度样式。
let props = defineProps({
value: Number,
theme: { type: String, default: 'orange' }
});
let width = ref(props.value);
const fontwidth = computed(() => `width:${width.value}em`);
定义自定义事件
我们使用 defineEmits
定义了一个名为 update-rate
的自定义事件。onRate
方法在用户点击星星时触发该事件,并将打分结果传递给父组件。
const emits = defineEmits(["update-rate"]);
const onRate = (num) => {
emits("update-rate", num);
};
鼠标交互实现
mouseOver
方法在鼠标悬停时更新 width
的值,从而改变实心星星的宽度,显示悬停效果。mouseOut
方法在鼠标移出时恢复 width
的值为 props.value
,显示原始打分值。
const mouseOver = (i) => {
width.value = i;
};
const mouseOut = () => {
width.value = props.value;
};
模板部分
<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>
在模板中,我们使用 v-for
循环生成 5 个空心星星和实心星星。空心星星在 mouseover
事件中调用 mouseOver
方法,实心星星在 click
事件中调用 onRate
方法并在 mouseover
事件中调用 mouseOver
方法。hollow
类的 span
元素的 style
属性绑定了 fontwidth
,用来动态设置实心星星的宽度。
样式部分
.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;
}
样式部分通过 position: relative
和 position: absolute
将实心星星定位在空心星星上面。rate
类设置为 relative
,确保实心星星的 absolute
定位是相对于 rate
容器。span.hollow
的 width
根据 fontwidth
动态调整,控制实心星星的显示宽度。
父子通信详解
在 Vue 3 中,父子组件的通信通常遵循以下原则:
- 数据状态及修改归父组件管理:父组件负责管理状态,并通过
props
将状态传递给子组件。子组件不能直接修改props
。 - 通过
props
和自定义事件传递数据:父组件将数据通过props
传递给子组件,子组件通过自定义事件将数据或事件结果传递回父组件。 - 子组件不可以直接修改状态:子组件通过自定义事件向父组件发送请求,让父组件修改状态。
在这个星星打分组件中,父组件通过 @update-rate="update"
自定义事件来接收子组件传递的打分结果:
<script setup>
import HelloWorld from './components/HelloWorld.vue'
import Rate from './components/Rate1.vue';
import {ref} from 'vue';
let score = ref(3)
function update(num) {
score.value = num
}
</script>
<template>
<div>
<Rate :value="score" theme="blue" @update-rate="update" />
<!-- vue中的数据通信 ,update-rate为自定义事件-->
</div>
</template>
父组件定义了一个 score
响应式变量,并将其传递给子组件。同时定义了一个 update
方法,用于接收子组件传递的打分结果并更新 score
的值。
子组件中,我们使用 defineEmits
定义自定义事件:
const emits = defineEmits(["update-rate"]);
const onRate = (num) => {
emits("update-rate", num);
};
当用户点击星星时,通过 emits
触发自定义事件,并将打分结果传递给父组件:
const onRate = (num) => {
emits("update-rate", num);
};
最终效果
总结
通过以上步骤,我们实现了一个从基础到复杂的星星打分组件,涵盖了主题颜色和动态交互功能,并详细讲述了 Vue 组件的 props、computed 和父子通信等知识。希望这篇文章对你在 Vue 3 中定制组件有所帮助。如果觉得这篇文章不错,可以点个赞😊。
转载自:https://juejin.cn/post/7389913087472451636