You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Next.js 星级评分问题:实现单次点击半星、双击全星效果

Next.js星级评分组件交互问题:半星效果无法实现

问题描述

开发Next.js星级评分组件时,期望实现以下交互:

  • 点击某颗星级第一次:该星级显示半填充状态
  • 点击某颗星级第二次:该星级显示全填充状态
    但当前点击任意星级一次会直接填满所有星级,无法触发半星效果。

代码问题分析

当前代码的核心问题在于:

  1. 所有星级的点击事件都直接将rating设置为index + 1(整数),没有处理半星的数值逻辑
  2. 没有判断当前点击的星级是否已经处于半星或全星状态,无法实现状态切换

解决方案

修改星级的点击逻辑,根据当前rating的值判断要切换的状态:

  • 如果当前rating小于index + 0.5:设置为半星值(index + 0.5)
  • 如果当前rating等于index + 0.5:设置为全星值(index + 1)
  • 如果当前rating已经是index + 1:可选择重置为0(或根据需求调整为其他逻辑)

同时调整星级渲染的判断逻辑,确保半星和全星的显示正确。

修改后的完整代码:

import { useState } from "react";
import styles from "./ModalFeedback.module.scss";

import useModal from "../../utils/useModal";
import { BsStar, BsStarHalf, BsStarFill } from "react-icons/bs";
import { createFeedback } from "../../utils/api/feedbackApi";

import ModalContainer from "./ModalContainer";
import Input from "../global/input/TextInput";
import { ButtonContainer, Button } from "../global/Button";
import { toast } from "react-toastify";

const ModalFeedback = () => {
    const [input, setInput] = useState({ message: "", rating: 0 });
    const [isLoading, setLoading] = useState(false);
    const { modal, setModal } = useModal("send-feedback");

    const submitHandler = () => {
        setLoading(true);
        createFeedback(input)
            .then((resolve) => {
                console.log(resolve);
                toast.info("Send feedback success.");
                setModal(false);
            })
            .catch((reject) => {
                console.log(reject);
                toast.error(reject);
            })
            .finally(() => {
                setLoading(false);
            });
    };

    // 处理星级点击的状态切换逻辑
    const handleStarClick = (index) => {
        const starValue = index + 1;
        const halfStarValue = index + 0.5;

        if (input.rating < halfStarValue) {
            // 当前未选中或小于半星,设置为半星
            setInput({ ...input, rating: halfStarValue });
        } else if (input.rating === halfStarValue) {
            // 当前是半星,设置为全星
            setInput({ ...input, rating: starValue });
        } else if (input.rating === starValue) {
            // 当前是全星,重置为未选中(可选逻辑,可按需调整)
            setInput({ ...input, rating: 0 });
        }
    };

    return (
        <ModalContainer
            show={modal}
            isLoading={isLoading}
            customContainer={{ padding: "1.5rem 1.875rem" }}
            onClose={() => {
                setInput({ message: "", rating: 0 });
            }}
        >
            <h5 className={styles.title}>Feedback</h5>
            <div className={styles.rating}>
                {Array.from({ length: 5 }, (_, index) => {
                    const starValue = index + 1;
                    const halfStarValue = index + 0.5;

                    if (input.rating >= starValue) {
                        return <BsStarFill onClick={() => handleStarClick(index)} key={index} />;
                    } else if (input.rating >= halfStarValue) {
                        return <BsStarHalf onClick={() => handleStarClick(index)} key={index} />;
                    } else {
                        return <BsStar onClick={() => handleStarClick(index)} key={index} />;
                    }
                })}
            </div>
            <Input label="Message">
                <textarea
                    className={styles.input}
                    rows={4}
                    placeholder="Fill in your feedback for us.."
                    value={input.message}
                    onChange={(e) => {
                        setInput({ ...input, message: e.target.value.substring(0, 250) });
                    }}
                />
            </Input>
            <p className={styles.info}>{input.message.length}/250 max characters</p>
            <ButtonContainer style={{ width: "24rem", gap: "1.5rem" }}>
                <Button style={{ flex: 1 }} isTransparent onClick={() => setModal(false)}>
                    Later
                </Button>
                <Button style={{ flex: 1 }} onClick={submitHandler} isDisabled={!input.rating} isLoading={isLoading}>
                    Send Feedback
                </Button>
            </ButtonContainer>
        </ModalContainer>
    );
};

export default ModalFeedback;

关键修改点

  • 新增handleStarClick函数,处理点击时的状态切换逻辑,实现半星和全星的切换
  • 调整星级渲染的判断条件,确保根据rating的数值正确显示对应图标
  • 点击全星后可选择重置为未选中,若不需要该逻辑,可删除对应分支

内容的提问来源于stack exchange,提问作者Kia Kalista

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.21 01:45:42