🎯 案例核心效果

  1. 页面展示 5 星评分控件,鼠标悬浮时实时高亮对应星级,点击可确认评分;
  2. 支持半星评分(精准到 0.5 星),满足更细致的评分需求;
  3. 选中评分后给出文字反馈(如 “非常满意”“一般”),交互体验更友好;
  4. 样式简约美观,支持自定义星级颜色、大小,适配 PC 和移动端;
  5. 代码精简可复用,核心逻辑封装成函数,便于集成到表单、商品评价等场景。

📌 实现思路(极简清晰)

分 3 步落地,逻辑简单易上手,零基础也能快速掌握:

  1. HTML:搭建评分容器,包含星级元素和反馈文本区域,结构极简;
  2. CSS:实现星级样式、悬浮 / 选中状态高亮,半星效果通过背景渐变实现;
  3. JS:监听鼠标悬浮 / 点击 / 离开事件→计算高亮星级→更新样式和反馈文本→保存最终评分。

🚀 完整源码(可直接复制运行)

html

预览

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>JS 星级评分组件 | 实战案例</title>
    <style>
        /* 全局重置(精简规范) */
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
            font-family: "Microsoft YaHei", sans-serif;
        }

        /* 页面布局:居中显示 */
        body {
            display: flex;
            flex-direction: column;
            align-items: center;
            justify-content: center;
            min-height: 100vh;
            padding: 20px;
            background-color: #f5f5f5;
        }

        /* 标题样式 */
        .title {
            font-size: 24px;
            color: #333;
            margin-bottom: 30px;
            text-align: center;
        }

        /* 评分容器 */
        .rating-container {
            display: flex;
            flex-direction: column;
            align-items: center;
            gap: 20px;
            width: 100%;
            max-width: 400px;
        }

        /* 星级容器:核心评分区域 */
        .stars-wrapper {
            position: relative;
            display: flex;
            font-size: 40px;
            color: #e4e4e4; /* 未选中星级颜色 */
            cursor: pointer;
        }

        /* 高亮星级层:通过宽度控制高亮范围 */
        .stars-highlight {
            position: absolute;
            top: 0;
            left: 0;
            height: 100%;
            overflow: hidden;
            color: #ffd700; /* 选中星级颜色(金色) */
            pointer-events: none; /* 禁止触发事件,避免遮挡底层 */
        }

        /* 反馈文本 */
        .feedback-text {
            font-size: 18px;
            color: #666;
            height: 24px;
            text-align: center;
        }

        /* 最终评分展示 */
        .result-text {
            font-size: 16px;
            color: #409eff;
            margin-top: 10px;
        }

        /* 移动端适配 */
        @media (max-width: 500px) {
            .title {
                font-size: 20px;
            }
            .stars-wrapper {
                font-size: 32px;
            }
            .feedback-text {
                font-size: 16px;
            }
        }
    </style>
</head>
<body>
    <h1 class="title">星级评分组件(支持半星)</h1>
    <div class="rating-container">
        <!-- 星级容器 -->
        <div class="stars-wrapper" id="starsWrapper">
            <!-- 高亮层:动态调整宽度实现星级高亮 -->
            <div class="stars-highlight" id="starsHighlight">★★★★★</div>
            <!-- 底层星级:用于鼠标交互 -->
            <div class="stars-base">★★★★★</div>
        </div>
        <!-- 反馈文本 -->
        <div class="feedback-text" id="feedbackText">请进行评分</div>
        <!-- 最终评分 -->
        <div class="result-text">最终评分:<span id="finalRating">0</span> 星</div>
    </div>

    <script>
        // 1. 获取DOM元素
        const starsWrapper = document.getElementById('starsWrapper');
        const starsHighlight = document.getElementById('starsHighlight');
        const feedbackText = document.getElementById('feedbackText');
        const finalRating = document.getElementById('finalRating');

        // 核心配置
        const starCount = 5; // 总星级
        let selectedRating = 0; // 最终选中的评分

        // 评分对应的文本反馈
        const feedbackMap = {
            0: '请进行评分',
            0.5: '极不满意',
            1: '非常不满意',
            1.5: '不满意',
            2: '不太满意',
            2.5: '一般',
            3: '还不错',
            3.5: '比较满意',
            4: '满意',
            4.5: '非常满意',
            5: '极致满意'
        };

        // 2. 计算鼠标位置对应的星级(核心逻辑)
        function calculateRating(e) {
            // 获取星级容器的位置和宽度
            const rect = starsWrapper.getBoundingClientRect();
            // 计算鼠标在容器内的相对位置(x轴)
            const x = e.clientX - rect.left;
            // 计算当前星级(精准到0.5星)
            let rating = (x / rect.width) * starCount;
            // 四舍五入到最近的0.5星
            rating = Math.round(rating * 2) / 2;
            // 限制星级范围
            rating = Math.max(0, Math.min(starCount, rating));
            return rating;
        }

        // 3. 更新星级高亮和反馈文本
        function updateRating(rating) {
            // 调整高亮层宽度,实现星级高亮
            starsHighlight.style.width = `${(rating / starCount) * 100}%`;
            // 更新反馈文本
            feedbackText.textContent = feedbackMap[rating] || feedbackMap[0];
        }

        // 4. 绑定鼠标悬浮事件:实时预览评分
        starsWrapper.addEventListener('mousemove', (e) => {
            const rating = calculateRating(e);
            updateRating(rating);
        });

        // 5. 绑定鼠标离开事件:恢复选中的评分
        starsWrapper.addEventListener('mouseleave', () => {
            updateRating(selectedRating);
        });

        // 6. 绑定点击事件:确认评分
        starsWrapper.addEventListener('click', (e) => {
            selectedRating = calculateRating(e);
            updateRating(selectedRating);
            // 更新最终评分展示
            finalRating.textContent = selectedRating;
        });

        // 初始化:默认显示0星
        updateRating(selectedRating);
    </script>
</body>
</html>

📖 核心代码拆解(重点突出,易懂好记)

1. HTML 结构(极简规整)

核心分为 2 部分,功能边界清晰:

  • stars-wrapper:星级容器,包含stars-highlight(高亮层)和stars-base(底层星级),通过两层叠加实现高亮效果;
  • feedback-text/result-text:反馈文本和最终评分展示区域,提升交互反馈体验。

2. CSS 样式(简约美观,交互友好)

重点关注 3 个核心样式:

  • 双层星级:底层显示灰色未选中星级,高亮层通过宽度控制金色星级的显示范围,实现星级高亮;
  • 指针事件禁用:给高亮层添加pointer-events: none,避免遮挡底层的鼠标交互;
  • 响应式适配:移动端缩小星级和文本尺寸,保证显示效果一致。

3. JS 逻辑(核心中的核心,分步拆解)

星级计算

  • 通过getBoundingClientRect()获取容器位置,计算鼠标相对位置;
  • 将鼠标位置转换为星级,四舍五入到 0.5 星,满足半星评分需求;
  • 限制星级范围在 0-5 之间,避免超出边界;

交互事件

  • mousemove:鼠标悬浮时实时计算并更新星级高亮和反馈文本;
  • mouseleave:鼠标离开时恢复到已选中的评分,避免预览状态残留;
  • click:点击时保存最终评分,更新展示区域;

反馈映射

  • 通过feedbackMap对象将评分与文本反馈绑定,提升用户感知;
  • 初始化时默认显示 0 星反馈,保证页面加载状态完整。

💡 新手常见踩坑点(精准避坑,少走弯路)

  1. 高亮层遮挡鼠标事件? → 未给stars-highlight添加pointer-events: none,导致鼠标无法触发底层交互,需禁用高亮层的事件响应;
  2. 半星评分不精准? → 未对计算出的星级做四舍五入到 0.5 星的处理,需添加Math.round(rating * 2) / 2
  3. 移动端评分错位? → 未使用getBoundingClientRect()获取实时位置,而是用固定宽度,需基于当前容器位置计算鼠标坐标;
  4. 鼠标离开后高亮不恢复? → 未在mouseleave事件中恢复选中的评分,需调用updateRating(selectedRating)
  5. 星级超出 5 星 / 低于 0 星? → 未限制星级范围,需添加Math.max(0, Math.min(starCount, rating))

🔧 扩展思路(落地性强,新手可练)

  1. 只读模式:添加配置项,支持设置只读评分(仅展示,不可交互);
  2. 自定义配置:支持自定义星级数量、颜色、大小,适配不同设计风格;
  3. 分数转换:添加评分与分数的转换(如 5 星 = 10 分,3.5 星 = 7 分),适配表单提交;
  4. 动画效果:添加星级高亮的过渡动画,提升交互流畅度;
  5. 批量评分:扩展为多组评分组件(如商品的 “质量”“服务”“物流” 多维度评分);
  6. 表单集成:添加隐藏输入框,选中评分后自动赋值,便于表单提交到后端。

🎯 核心知识点总结(凝练精准,实战导向)

  1. 鼠标位置计算:掌握getBoundingClientRect()获取元素位置,实现精准的鼠标交互;
  2. 视觉分层:通过双层元素叠加 + 宽度控制,实现动态高亮效果;
  3. 事件组合:结合mousemove/mouseleave/click实现完整的交互闭环;
  4. 数据映射:通过对象映射实现评分与文本的关联,提升代码可维护性;
  5. 边界处理:对计算结果做范围限制,保证程序健壮性;
  6. 响应式交互:适配不同设备的鼠标 / 触摸交互,保证体验一致。

📢 互动留言

跟着案例实操一遍,轻松实现带半星的星级评分组件!这个功能在商品评价、表单反馈、问卷调查等场景中高频使用,复制代码就能直接复用。如果遇到半星不精准、高亮层遮挡事件等问题,评论区留言,我会第一时间解答;你还想给评分组件添加哪些扩展(比如只读模式、自定义颜色),也可以留言告诉我~

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐