likes
comments
collection
share

制作一个有趣的打分小组件,评价为“五星上将”,理解计算属性

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

正文

今天来制作一个有趣的交互式小操作

为店铺或者商品的打分小组件

(给出如下的例子:美团订单的评分以及抖音团购的评分)

制作一个有趣的打分小组件,评价为“五星上将”,理解计算属性 制作一个有趣的打分小组件,评价为“五星上将”,理解计算属性

自己来写几个星星

从易到难,先写出几个基础的星星

<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 lang="css" scoped>

</style>

使用了Vue的definePropscomputed方法。defineProps用于定义组件的props,

定义了一个名为value的Number类型prop。

computed方法创建了一个计算属性rate,它根据props.value的值来截取字符串"★★★★★☆☆☆☆☆"的一部分,从而动态地生成评分的星星图标。

最终,在模板中通过双括号语法{{ rate }}来显示计算后的评分。

defineProps是Vue 3中用于在组合API (Composition API) 中声明组件props的一个重要函数。它允许你显式地定义组件预期从父组件接收的属性(props),并为这些属性提供类型检查、默认值以及其他元信息。

以下是defineProps的主要作用:

  1. 类型检查defineProps让你能够为每个prop指定其预期的类型,例如StringNumberBooleanArrayObjectFunction, 或者自定义构造函数。这有助于防止错误类型的值被传递给组件。
  2. 默认值: 你可以为每个prop定义默认值,当父组件没有传递该prop时,组件将使用这个默认值。
  3. 响应式处理defineProps返回一个响应式的代理对象,这意味着当父组件更改prop的值时,子组件会自动更新以反映新的状态。

computed是Vue.js框架中的一种属性类型,用于在组件中定义依赖于其他数据的计算属性。 computed在该代码片段中主要负责根据输入的value属性动态计算出一个表示评分的字符串,

在主页面中生成出分别为5、4、3、2颗实星星

<template>
  <div>
    <Rate :value="5"/>
    <Rate :value="4"/>
    <Rate :value="3"/>
    <Rate :value="2"/>
  </div>
</template>

<script setup>
import { ref } from "vue";
import Rate from "./components/Rate0.vue";
</script>

制作一个有趣的打分小组件,评价为“五星上将”,理解计算属性

而我们需要将这些星星全都变为响应式的才能发挥出其评分的作用 需要明确的是,星星的显示样式(实心或空心)应该基于它们的索引和当前的评分值(props.value)。通常情况下,索引小于等于评分值的星星应该是实心的,其他星星则是空心的。

为了实现点击或鼠标悬停时改变星星样式的功能,我们可以这样做:

  1. 定义星星的样式:在CSS中,我们可以定义两种样式类,一种是.filled用于实心星星,另一种是.hollow(或不加这个类,直接用默认样式)用于空心星星。
  2. 使用v-for渲染星星:在模板中,我们使用v-for指令来遍历星星的数量(比如5颗)。对于每一颗星星,我们根据它的索引和评分值来决定是否应用.filled样式类。
  3. 添加点击和鼠标悬停事件:我们可以为每颗星星添加@click@mouseover事件监听器。当星星被点击时,我们更新评分值并重新渲染星星;当鼠标悬停在星星上时,我们临时改变星星的样式为实心(如果需要预览效果的话)。
<template>
    <div :style="fontStyle"><!-- style 绑定将把 fontStyle 数据属性(或计算属性) -->
        <div class="rate" @click="changeJudge" @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>
            <!-- {{ rate }} -->
        </div>
    </div>
    <!-- <button @click="onRate(1)">1</button> -->
</template>

<script setup>
// 新的需求 添加主题 改变不同风格的⭐
import { ref,defineProps,computed,defineEmits } from 'vue'
// 自身的状态

let props = defineProps({
        value: Number,
        theme: {type:String,default:'purple'}

})

let width = ref(props.value)
let fontwidth = computed(() => `width: ${width.value}em;`)

let themeObj = {
    orange: '#ffa500',
    blue: '#0000ff',
    green: '#008000',
    red: '#ff0000',
    purple: '#800080',
    pink: '#ffc0cb',
    yellow: '#ffff00',
    gray: '#808080',
    black: '#000000',
    white: '#ffffff',
}

let rate = computed(() => "★★★★★☆☆☆☆☆".slice(5-props.value, 10-props.value))

const fontStyle = computed(() => {
    return `color: ${themeObj[props.theme]}`//themeObj配置项
})

let emits = defineEmits(["update-rate"])

const onRate = (num) => {
    emits("update-rate", num)
}

let Judge = false
const changeJudge = () => {
    Judge =! Judge
}

function mouseOver(i) {
    if(Judge){
        return
    }
    width.value = i
}
function mouseOut() {
    width.value = props.value
}

</script>

<style>
    .rate {
        position: relative;
        display: inline-block;
    }
    .rate span {
        /* letter-spacing: 3px; */
        display: inline-block;
        width: 1rem;
        height: 22px;
        overflow: hidden;
    }
    .rate > span.hollow {
        position: absolute;
        display:inline-block;
        top:0;
        left:0;
        width:0;
        overflow:hidden;
    }
</style>

1. 模板部分 (<template>)

  • 外层div:使用了:style="fontStyle"来动态绑定样式,这里预期是绑定星星的颜色

  • 评分区域<div class="rate">内部包含了两个span元素,分别用于显示已评分的星星(实心)和未评分的星星(空心)。

    • 实心星星:通过v-for="num in 5"循环生成5个星星,每个星星的mouseover事件触发mouseOver方法,用于预览评分效果。
    • 空心星星:包裹在span class="hollow"内,通过计算属性fontwidth(但这里其实用错了,应该是用来控制空心星星的显示宽度)和另一个v-for循环生成。这些星星的clickmouseover事件同样触发相关方法。

2. 脚本部分 (<script setup>)

  • Props:定义了value(当前评分)和theme(主题颜色)两个props。

  • Refs和Computed Properties

    • width:用于临时存储鼠标悬停时的评分预览值。
    • fontwidth:用于控制空心星星的显示宽度。
    • themeObj:定义了不同主题对应的颜色。
    • fontStyle:同样是语法错误,应该返回一个对象,如{ color: themeObj[props.theme] },用于绑定到外层div的样式上。
  • Emits:定义了update-rate事件,用于子组件向父组件通信评分的变化。

  • Methods

    • onRate:点击星星时触发,通过emits发送评分到父组件。
    • changeJudge:切换一个名为Judge的变量,。
    • mouseOvermouseOut:分别处理鼠标悬停和移出时的逻辑,mouseOver用于预览评分,mouseOut用于恢复原始评分显示。

3. 样式部分 (<style>)

  • .rate:定义了评分区域的基本样式,包括位置、显示方式和内联块级元素的特性。
  • .rate span:为星星设置了宽度、高度和溢出隐藏,确保星星按照固定大小显示。
  • .rate > span.hollow:特别为空心星星设置了绝对定位,使其能够覆盖在实心星星之上,并通过改变宽度来显示未评分的星星。

渲染出评分的星星吧

<template>
  <div>
    <Rate0 :value="score" theme="orange" @update-rate="updata" />
  </div>
</template>

<script setup>
import { ref } from "vue";
import Rate0 from "./components/Rate1.vue";

let score = ref(0);
function updata(num){
  score.value = num;
}
</script>

<Rate0> 组件通过 :value 绑定了 score 的值,通过 theme 属性设置了样式主题为橙色,监听了 update-rate 事件,当该事件触发时,updata 函数会被调用,从而更新 score 的值。这种机制允许 Rate0 组件内部改变其绑定的值,并且这种变化可以被外部组件感知和响应。

默认为全是空星,鼠标移到哪里就变为鼠标下的实星数

制作一个有趣的打分小组件,评价为“五星上将”,理解计算属性

制作一个有趣的打分小组件,评价为“五星上将”,理解计算属性

结语

<div :style="fontStyle">

在Vue.js中,:style 是一个绑定指令,用于将CSS样式动态地应用到元素上。这里,fontStyle 是一个在Vue实例的data选项中定义的对象,该对象包含了要应用到<div>元素上的CSS样式属性。( 绑定为 fontStyle 数据属性(或计算属性))

let props = defineProps({
        value: Number,
        theme: {type:String,default:'purple'}

})

defineProps 是一个用于在组件内部声明接收的 prop 的方法,- defineProps 是一个函数,它接收一个对象作为参数,这个对象描述了组件期望接收的所有 prop 的类型和默认值。

let emits = defineEmits(["update-rate"])

const onRate = (num) => {
    emits("update-rate", num)
}

defineEmits 提供了一种机制,让组件可以与外部环境(通常是父组件)进行通信,通过触发自定义事件来通知状态的变化或请求某些操作。当子组件触发 "update-rate" 事件时,updata 函数将被调用,并接收到从子组件传递过来的新评分值作为参数。

转载自:https://juejin.cn/post/7389653171961053199
评论
请登录