原生JS实现星级评分系统:从原理到完整代码

作者:像素漫游

时间:2026-10-30

浏览:403

本文详细介绍如何使用原生JavaScript实现一个可自定义星星数量和显示信息的星级评分系统。文章涵盖CSS三角形绘制、绝对定位、事件代理、正则表达式匹配及IE兼容性处理等核心技术点,并提供带详细注释的完整代码示例,帮助开发者巩固前端基础知识并提升实战能力。

文章目录

星级评分系统基础与调用示例

今天分享一个实用的前端小案例:星级评分系统,该功能支持自定义星星数量及动态显示提示信息。基础调用方式如下: sufuStar.star(); 此方法使用默认配置,即显示5颗星星,并附带默认提示信息。

若需自定义星星数量及提示内容,可传入参数: var msg = [........]; sufuStar.star(10,msg);

在上述调用中,第一个参数指定星星数量为10,第二个参数msg为提示信息数组。注意,msg数组的长度必须与星星数量保持一致,以确保显示信息对应正确。

通过亲手实现此类实例,不仅能加深对各类知识点的理解与应用熟练度,还能有效暴露个人知识盲区。一旦发现薄弱环节,应立即查阅API文档进行针对性强化学习。

尽管这是一个基础案例,但为了完善细节和兼容性,实际开发耗时较长,本人花费了整整一天时间才完成该实例的编写。

核心技术点解析

接下来,梳理该实例所涉及的核心技术点:

1. 利用CSS的border属性绘制三角形,并通过::before伪元素将其插入到目标元素中;

2. 掌握CSS元素定位技巧,确保星星图标排列整齐;

3. 应用事件代理机制,提高事件监听效率;

4. 关注代码性能优化,减少不必要的DOM操作;

5. 使用String对象的match方法结合正则表达式进行数据匹配;

6. 处理事件注册与事件处理逻辑,需特别注意兼容IE浏览器的写法;

7. 利用逻辑或运算符‘||'为变量设置默认值,增强代码健壮性;

8. 代码简化策略:将重复使用的逻辑提取为独立函数,提高代码复用率。

以下是带有详细注释的完整代码实现。遇到不理解的逻辑请查阅相关文档,以当前水平已尽力完善,若有更优建议,欢迎指正!

完整代码实现


<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title></title>
  <style>
    *{
      margin: 0;
      padding: 0;
    }
    #star{
      position: absolute;
      left: 0;
      right: 0;
      top: 30px;
      bottom: 0;
      margin: auto;
      width: 80%;
      font-size: 12px;
    }
    #star-div{
      margin:5px;
      font-size: 0;
    }
    #star-div a{
      display: inline-block;
      width: 21px;
      height: 21px;
      background: url(http://files.cnblogs.com/files/susufufu/star0.gif) no-repeat;

    }
    #star-div .on{
      background: url(http://files.cnblogs.com/files/susufufu/star1.gif) no-repeat;
    }
    #star-info{
      position: absolute;
      top: 55px;
      left: -30px;
      display: none;
      width: 155px;
      height: 50px;
      padding: 2px;
      line-height: 17px;
      border-radius: 8px;
      background-color: gold;
      z-index: 5;
    }
    #star-info:before{
      content: '';
      border-bottom: 10px solid gold;
      border-left: 10px solid rgba(0,0,0,0);
      border-right: 10px solid rgba(0,0,0,0);
      position: absolute;
      left: 35px;
      top: -10px;
    }
    #star-span{line-height: 14px}
    #star-info strong,#star-span strong{
      color: red;
    }
  </style>
  <script>
    window.onload = function(){
      var sufuStar = function (){
        //工具函数
        function gbyId(id){return document.getElementById(id);}

        function addEvent(elem,type,func){ //兼容IE
          if(elem.addEventListener){
            elem.addEventListener(type,func,false)
          }else if(elem.attachEvent){
            elem.attachEvent('on'+type,func)
          }
        }
        function getIndex(event) { //兼容IE
          var e = event || window.event;
          var t = e.target || e.srcElement;
          if (t.tagName.toLowerCase() === 'a') {
            return parseInt(t.innerHTML);
          }
        }
        function showInfo(index,msg){
          var info = gbyId('star-info');
          info.style.display = 'block';
          info.style.left = index*21-51+'px';
          info.innerHTML = "<strong> "+index+'分 '+msg[index-1].match(/(.+)\|/)[1]+'<br />'+'</strong>'+msg[index-1].match(/\|(.+)/)[1];
        }
        function appenStar(elem,nums){
          var frag = document.createDocumentFragment(); //为了提高性能,因使用DocumentFragment一次性append,这样页面只重新渲染一次
          for(var i = 0;i<nums;i++){
            var a =document.createElement('a');
            a.innerHTML = i+1;
            a.href = "javascript:;"; //阻止浏览器的点击链接的默认行为
            frag.appendChild(a);
          }
          elem.appendChild(frag);
        }
        //主体函数
        function star(num,myMsg){
          var n = num||5; //当num有值则取其值,无值则取默认值5;
          var clickStar=curentStar=0; //clickStar保存点击状态
          var msg = myMsg||[
            "很不满意|差得太离谱,与卖家描述的严重不符,非常不满",
            "不满意|部分有破损,与卖家描述的不符,不满意",
            "一般|质量一般,没有卖家描述的那么好",
            "满意|质量不错,与卖家描述的基本一致,还是挺满意的",
            "非常满意|质量非常好,与卖家描述的完全一致,非常满意"
          ];
          var starContainer = gbyId('star-div');
          appenStar(starContainer,n);
          addEvent(starContainer,'mouseover',over); //采用事件代理模式(通过<a>标签的父元素starContainer来代理事件)
          addEvent(starContainer,'mouseout',out);
          addEvent(starContainer,'click',click);
          function over(event){
            if(getIndex(event)){ //若getIndex(event)取不到值,说明当前触发事件的目标不是<a>标签
              var index = getIndex(event);
              change(index);
              showInfo(index,msg);
            }
          }
          function out(event){
            change(); //将评分设为已点击状态clickStar
            gbyId('star-info').style.display = 'none'
          }
          function click(event) {
            if (getIndex(event)) {
              var index = getIndex(event);
              clickStar = index; //保存点击状态
              gbyId('star-info').style.display = 'none';
              gbyId('star-span').innerHTML = "<strong>" + index + '分 ' + msg[index - 1].match(/(.+)\|/)[1] + '</strong>'+'<br />'+ msg[index - 1].match(/\|(.+)/)[1];
            }
          }
          function change(index){
            curentStar = index||clickStar;
            for(var i=0;i<n;i++){
              starContainer.children[i].className = i<curentStar ? 'on' : ''
            }
          }
        }
        return {
          star:star
        }
      }(); //这里的()表示函数立即执行,这样变量sufuStar才能调用匿名函数的返回值star

      //调用执行: sufuStar.star(num,myMsg),参数可为空,参数num,myMsg将设为默认值
      sufuStar.star();
    }
  </script>
</head>
<body>
<div id="star">
  <span>点击星星打分:</span>
  <div id="star-div">
  </div>
  <span id="star-span"></span>
  <p id="star-info">
  </p>
</div>
</body>
</html>

以上关于原生JS实现星级评分系统的完整教程到此结束,希望能为各位开发者提供参考。如有任何问题或建议,欢迎交流探讨,并感谢支持本站。

实用工具推荐

电子包浆

绿化、压缩、噪点和虚拟水印,自由调节做旧程度。

使用 ›
图片压缩

选择画质和输出格式,预览压缩前后的大小。

使用 ›
相关文章