Next.js 星级评分问题:实现单次点击半星、双击全星效果
Next.js星级评分组件交互问题:半星效果无法实现
问题描述
开发Next.js星级评分组件时,期望实现以下交互:
- 点击某颗星级第一次:该星级显示半填充状态
- 点击某颗星级第二次:该星级显示全填充状态
但当前点击任意星级一次会直接填满所有星级,无法触发半星效果。
代码问题分析
当前代码的核心问题在于:
- 所有星级的点击事件都直接将
rating设置为index + 1(整数),没有处理半星的数值逻辑 - 没有判断当前点击的星级是否已经处于半星或全星状态,无法实现状态切换
解决方案
修改星级的点击逻辑,根据当前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
相关产品推荐
相关产品推荐

