点亮你的星级评价 —— Vue.js中的评分组件设计之旅

624 阅读5分钟

前言

在数字化时代,评分系统已成为各类在线平台不可或缺的一部分,从外卖应用的美食评价,到影视平台的观影打分,再到电子商务的商品评级,星级评分不仅加深了用户与产品的互动,还为商家提供了宝贵的用户反馈,促进了产品和服务的持续优化。今天,我们就开始学习亲手打造一个能够实现星级评分的小组件。

正文

分析需求

我们想要实现是动态效果样式为:

动画6.gif 为了实现组件的功能,我们需要实现的需求具体如下:

  1. 分数的动态显示

    • 当用户将鼠标悬停在星星上时,应即时显示当前悬停的星星及其以下所有星星的高亮状态,以直观反映可能的评分。
    • 用户完成评分后,应清晰展示最终评分结果。
  2. 主题定制功能

    • 系统应提供可配置的主题选项,包括但不限于星星的颜色、大小、形状及背景样式,以适应不同的网站设计风格。
  3. 鼠标悬停(mouseover)事件处理

    • 当鼠标悬停在某颗星星上时,应触发事件,以提示用户当前的潜在评分值。
  4. 鼠标离开(mouseout)事件处理

    • 当鼠标离开星星区域时,应恢复到之前的状态,除非已经完成了评分。
  5. 点击(click)事件响应

    • 用户点击星星时,应记录并提交用户的评分选择,反映最新的评分状态。

了解了需求后我们开始第一步,创建vue项目==>

创建项目

  1. 在集成终端上运行下列代码创建一个vue项目
npm init vite
  1. 选择Vue和JavaScript,命名这里取的是rate

屏幕截图 2024-07-11 171449.png

image.png 在vue的文件夹下运行完成后

  1. 在终端里输入
cd rate
  1. 来到vue里刚刚创建的rate目录下输入下行命名添加依赖
npm i
  1. 添加Rate.vue和App.vue文件

项目目录:

image.png

此时项目框架就已经配置好了

定制组件

Rate.vue

<template>部分:

  • div内部,有一个带有两个span元素的rate div:一个用于未评级的部分(),另一个用于已评级的部分()。

该组件通过鼠标悬停点击事件来更新评级。

当用户将鼠标悬停在某个星星上时,会高亮显示从第一个星到该星的所有星星。

当鼠标移出时,高亮显示会回到当前的评分值。

点击星星时,组件会发出一个update-score事件,将新的评分值传递给父组件。

 <div :style="fontStyle">
    <div class="rate" @mouseout="mouseOut">
      <span class="star" @mouseover="mouseOver(num)" v-for="num in 5" :key="num"></span>
      <span class="hollow" :style="fontWidth">
        <span class="star" @click="onRate(num)" @mouseover="mouseOver(num)" v-for="num in 5" :key="num"></span>
      </span>
    </div>
  </div>

<script setup>设置部分:

  • 定义scoretheme属性,分别用于接收初始评分和主题颜色。
  • 使用计算属性fontStyle来根据主题颜色动态设置文本颜色。
  • rate计算属性用于生成表示当前评分的字符串
  • fontWidth计算属性用于设置已评级星星的宽度,使其与当前评分值相匹配(这里实际上会有差别,因为'★'和'☆'的宽度有略微不同)。

空心☆: image.png

实心★: image.png

  • width引用用于存储鼠标悬停或点击时的临时评分值。
  • onRate函数用于处理点击事件,触发update-score事件以通知父组件更新评分。
  • mouseOvermouseOut函数分别处理鼠标悬停和移出事件,更新width值以反映当前状态。
import { defineProps, computed, defineEmits, ref } from 'vue'
let props = defineProps({
  score: {//接收初始评分
    type: Number,。
    default: 0
  },
  theme: {//接收主题颜色
    type: String,
    default: 'blue'
  }
})
// 主题可定制性 
const themeObj = {//这里编辑了四种颜色样式
  'black': '#000',
  'yellow': '#fadb14',
  'blue': '#40a9ff',
  'green': '#73d13d'
}

//生成表示当前评分的字符串
let rate = computed(() => "★★★★★☆☆☆☆☆".slice(5 - props.score,10 - props.score))

//根据主题颜色动态设置文本颜色
const fontStyle = computed(() => {
  return `color: ${themeObj[props.theme]};`
})

// 私有状态  mouseover  mouseout  改变
let width = ref(props.score);

//通知父组件更新评分
let emits = defineEmits(['update-score'])
const onRate = (num) => {
  emits('update-score', num)
}

const fontWidth = computed(() => `width:${width.value}em;`)
const mouseOver = (num) => {
  width.value = num
}

const mouseOut = () => {
  width.value = props.score
}

<style>部分:

  • .star:设置星星之间的间距。
  • .rate:定位和显示整个评分组件。
  • .hollow:绝对定位已评级星星的部分,确保它们覆盖在未评级星星之上,同时限制其宽度以正确显示评分。
.star {
  letter-spacing: 3px;
}
.rate {
  position: relative;
  display: inline-block;
}
.rate>span.hollow {
  position: absolute;
  display: inline-block;
  top: 0;
  left: 0;
  overflow: hidden;
}

分数的显示

App.vue:

<script setup>部分:

//显示打分
import Rate from './components/Rate.vue'
import { ref } from 'vue'

let score = ref(3)//定义初始评分为3

function update(num) {
  score.value = num
}
  • 导入组件:首先,从当前目录下的 components 文件夹中导入 Rate 组件。
  • 使用 ref 创建响应式数据:通过 import { ref } from 'vue' 导入了 ref 函数,用于创建一个响应式的 score 数据,初始值为 3
  • 定义 update 函数:这个函数接收一个参数 num,用于更新 score 的值。它将接收到的数值赋给了 score.value,这是因为 ref 创建的数据是一个引用类型,需要通过 .value 来访问或修改其实质内容。

完整代码:

<template>
  <div :style="fontStyle">
    <div class="rate" @mouseout="mouseOut">
      <span class="star" @mouseover="mouseOver(num)" v-for="num in 5" :key="num"></span>
      <span class="hollow" :style="fontWidth">
        <span class="star" @click="onRate(num)" @mouseover="mouseOver(num)" v-for="num in 5" :key="num"></span>
      </span>
    </div>
  </div>
</template>
<script setup>
import { defineProps, computed, defineEmits, ref } from 'vue'
let props = defineProps({
  score: {
    type: Number,
    default: 0
  },
  theme: {
    type: String,
    default: 'blue'
  }
})
// 主题可定制性 
const themeObj = {
  'black': '#000',
  'yellow': '#fadb14',
  'blue': '#40a9ff',
  'green': '#73d13d'
}

let rate = computed(() => "★★★★★☆☆☆☆☆".slice(5 - props.score,
  10 - props.score))
const fontStyle = computed(() => {
  return `color: ${themeObj[props.theme]};`
})
// 私有状态  mouseover  mouseout  改变
let width = ref(props.score);

let emits = defineEmits(['update-score'])
const onRate = (num) => {
  emits('update-score', num)
}

const fontWidth = computed(() => `width:${width.value}em;`)
const mouseOver = (num) => {
  width.value = num
}

const mouseOut = () => {
  width.value = props.score
}

</script>
<style>
.star {
  letter-spacing: 3px;
}

.rate {
  position: relative;
  display: inline-block;
}

.rate>span.hollow {
  position: absolute;
  display: inline-block;
  top: 0;
  left: 0;
  overflow: hidden;
}
</style>

定制主题

可以根据需求自定义评分的颜色样式

<template> 部分:

  <div>
    <Rate @update-score="update" :score="score" theme="black" />
    <Rate @update-score="update" :score="score" theme="yellow" />
    <Rate @update-score="update" :score="score" theme="blue" />
    <Rate @update-score="update" :score="score" theme="green" />
  </div>

这部分用来定义组件的模板结构。

  • 使用 Rate 组件:在模板中,Rate 组件被使用,传入了 score 和 theme 属性,以及一个 @update-score 事件处理器,该处理器会在 Rate 组件触发 update-score 事件时调用 update 函数。

完整代码:

<script setup>
//显示打分
import Rate from './components/Rate.vue'
import { ref } from 'vue'

let score = ref(3)//定义初始评分为3

function update(num) {
  score.value = num
}
</script>

<template>
  <div>
    <Rate @update-score="update" :score="score" theme="black" />
    <Rate @update-score="update" :score="score" theme="yellow" />
    <Rate @update-score="update" :score="score" theme="blue" />
    <Rate @update-score="update" :score="score" theme="green" />
  </div>
</template>

<style scoped></style>

结语

以上就是本文的全部内容,评分组件使用广泛,希望本文对你的项目开发与对组件的掌握有所帮助,感谢你的阅读!