likes
comments
collection
share

大厂都在用的定制化组件,赶紧来掌握一下吧!

作者站长头像
站长
· 阅读数 24

引言

定制化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 定位,把实心星星叠加在空心星星上。

通过鼠标悬停和点击设置实心星星的宽度:鼠标悬停时,设置实心星星的宽度来显示悬停的效果;点击时,通过自定义事件将打分结果传递给父组件,更新实心星星的宽度,超出宽度的实心星星被隐藏从而达到悬停或点击星星就有几颗实心星星的效果。

首先我们定义了 valuetheme 两个 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: relativeposition: absolute 将实心星星定位在空心星星上面。rate 类设置为 relative,确保实心星星的 absolute 定位是相对于 rate 容器。span.hollowwidth 根据 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
评论
请登录