星级评分的实现

本文介绍了如何实现星级评分功能,详细阐述了原生JS和Vue两种版本的实现方法。在鼠标移入、离开和点击星星时,系统能动态更新激活状态。Vue版中,还封装了一个StarEvaluation组件,支持只读和可写两种模式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

星级评分的实现

星级评分是一种常见的打分方式,一般满分为5颗星,用户通过勾选星星的数量来给产品的某一维度进行打分,效果如下图所示:
在这里插入图片描述

当鼠标移动到某个星星上面时,当前星星及其前面的星星需处于激活状态;当鼠标移开时,所有星星恢复原状;只有当鼠标点击某个星星时,当前星星及其前面的星星处于激活状态,评分生效,此时鼠标移开时,星星状态不用恢复原状。

从上述分析可以看出,用到了鼠标进入、离开事件、以及点击事件,当移入到或点击某个星星时,需要确定出当前触发的是第几个星星,然后将当前星星及其前面的星星置为激活状态;离开星星时,如果之前没有触发点击事件,则需要将星星状态还原,具体实现如下:

原生js版

用html画出五个星星:

<div class="star-evaluation-wrapper">
  <span class="star">&#9733;</span>
  <span class="star">&#9733;</span>
  <span class="star">&#9733;</span>
  <span class="star">&#9733;</span>
  <span class="star">&#9733;</span>
</div>
<div class="result"></div>

星星的样式:

star{
  font-size: 18px;
  color: #666;
}
.star.active{
  color: #F78233;
}

评分逻辑:

const resultEle = document.querySelector('.result')
// 全局变量,用于存放用户的评分
let score = 0
const starWrapperEle = document.querySelector('.star-evaluation-wrapper')
const starEle = starWrapperEle.querySelectorAll('.star')
// 遍历每个星星元素,为每个星星添加索引、鼠标进入事件(onmouseenter)、以及点击事件
// 利用事件代理为星星容器添加鼠标移出事件(onmouseleave)
for (let i = 0; i < starEle.length; i++) {
  // 添加索引
  starEle[i].index = i
  // 添加鼠标进入事件
  starEle[i].onmouseenter = function (e) {
    // 将鼠标移入到的当前星星以及其前面的星星设置为激活状态,剩余的恢复原状
    for (let j = 0; j < starEle.length; j++) {
      if (j > this.index) {
        starEle[j].classList.remove('active')
      } else {
        starEle[j].classList.add('active')
      }
    }
    // 将鼠标移入时的评分显示出来
    resultEle.innerHTML = this.index + 1
  }
  // 通过事件代理给星星的容器添加鼠标移出事件
  starWrapperEle.onmouseleave = function (e) {
    // 鼠标移出时需判断全局变量score是否有值,有值的话鼠标离开时,需将score值对应的星星保持激活状态,否则将星星状态还原
    for (let j = 0; j < starEle.length; j++) {
      if (j > score - 1) {
        starEle[j].classList.remove('active')
      } else {
        starEle[j].classList.add('active')
      }
    }
    // 鼠标离开时将评分显示出来
    resultEle.innerHTML = score
  }
  // 为每个星星添加点击事件
  starEle[i].onclick = function (e) {
    for (let j = 0; j < starEle.length; j++) {
      // 点击某个星星时,需将该星星及其前面的星星置为激活状态
      if (j > this.index) {
        starEle[j].classList.remove('active')
      } else {
        starEle[j].classList.add('active')
      }
    }
    // 保存评分
    score = this.index + 1
    // 将评分显示出来
    resultEle.innerHTML = score
  }
}

vue版

封装出的StarEvaluation组件:

<template>
  <div class="star-evaluation-wrapper">
    <div :class="['star-wrapper', {'read-only': readOnly}]">
      <span :class="['star', {'active': value > 0}]">&#9733;</span>
      <span :class="['star', {'active': value > 1}]">&#9733;</span>
      <span :class="['star', {'active': value > 2}]">&#9733;</span>
      <span :class="['star', {'active': value > 3}]">&#9733;</span>
      <span :class="['star', {'active': value > 4}]">&#9733;</span>
    </div>
  </div>
</template>

<script>
export default {
  name: 'star-evaluation',
  props: {
    value: {
      type: Number,
      default: 0,
    },
    readOnly: {
      type: Boolean,
      default: false,
    },
  },
  data() {
    return {
    };
  },
  mounted() {
  	// 只读模式时不可以评分
    if (!this.readOnly) {
      this.evaluate();
    }
  },
  methods: {
  	// 评分逻辑
    evaluate() {
      const starWrapperEle = this.$el.querySelector('.star-wrapper');
      const starEle = starWrapperEle.querySelectorAll('.star');
      for (let i = 0; i < starEle.length; i++) {
        starEle[i].index = i;
        starEle[i].onmouseenter = (e) => {
          // 与原生js不一样,此处不可以用this表示当前遍历的星星,而是指向当前组件,因此用变量_this储存当前遍历的星星
          const _this = starEle[i];
          for (let j = 0; j < starEle.length; j++) {
            if (j > _this.index) {
              starEle[j].classList.remove('active');
            } else {
              starEle[j].classList.add('active');
            }
          }
        };
        starWrapperEle.onmouseleave = (e) => {
          for (let j = 0; j < starEle.length; j++) {
            if (j > this.value - 1) {
              starEle[j].classList.remove('active');
            } else {
              starEle[j].classList.add('active');
            }
          }
        };
        starEle[i].onclick = (e) => {
          const _this = starEle[i];
          for (let j = 0; j < starEle.length; j++) {
            if (j > _this.index) {
              starEle[j].classList.remove('active');
            } else {
              starEle[j].classList.add('active');
            }
          }
          this.$emit('input', _this.index + 1);
        };
      }
    },
  },
};
</script>

<style lang="scss" scoped>
.star-evaluation-wrapper{
  .star-wrapper{
    cursor: pointer;
    &.read-only{
      cursor: default;
    }
    .star{
      margin-right: 8px;
      font-size: 18px;
      color: #666;
      &.active{
        color: #F46200;
      }
    }
  }
}
</style>

StarEvaluation组件有两种模式,一种是只读模式,仅用于展示分数;另一种是可写模式,可以进行评分;使用方法如下:

// 可写模式
<star-evaluation v-model="score"></star-evaluation>
// 只读模式
<star-evaluation v-model="score" :read-only="true"></star-evaluation>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值