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

如何将实现骰子滚动功能的jQuery代码转换为React可用代码?

jQuery 骰子逻辑迁移 React 实现方案

React 开发核心是状态驱动视图,不要手动操作DOM,你原来的CSS可以100%复用,只需要把DOM操作逻辑替换成React状态管理即可,以下是可直接使用的函数组件实现(基于React 16.8+ Hooks语法,是目前主流写法):

逻辑对应关系

  • 原jQuery中手动存的临时变量(定时器ID、上一次掷出的点数)用useRef存储,这类值变化不需要触发界面重渲染
  • 原代码里手动给元素加/删class、改data-face属性的操作,全部通过state变化自动驱动渲染,不需要手动查找DOM修改
  • 原代码里给元素绑定的点击事件,直接写在对应JSX标签的onClick属性上,不需要提前选择DOM绑定监听
  • 组件卸载时必须清除未执行的定时器,避免内存泄漏

完整实现代码

import { useState, useRef, useEffect } from 'react';

const DiceRoller = () => {
  // 固定配置项
  const SIDES = 20;
  const INITIAL_SIDE = 1;
  const ANIMATION_DURATION = 3000;

  // 视图相关状态,变化会自动触发界面更新
  const [currentFace, setCurrentFace] = useState(INITIAL_SIDE);
  const [isRolling, setIsRolling] = useState(false);
  const [activeNav, setActiveNav] = useState(INITIAL_SIDE);

  // 非视图状态,变化不触发重渲染
  const lastFaceRef = useRef(null);
  const timerRef = useRef(null);

  // 组件卸载时清理定时器
  useEffect(() => {
    return () => {
      if (timerRef.current) clearTimeout(timerRef.current);
    }
  }, []);

  // 生成不和上一次重复的随机点数
  const getRandomFace = () => {
    let face = Math.floor(Math.random() * SIDES) + INITIAL_SIDE;
    if (face === lastFaceRef.current) face = getRandomFace();
    lastFaceRef.current = face;
    return face;
  };

  // 重置骰子状态
  const resetDice = () => {
    if (timerRef.current) clearTimeout(timerRef.current);
    setIsRolling(false);
    setCurrentFace(null);
  };

  // 滚动到指定点数
  const rollTo = (face) => {
    if (timerRef.current) clearTimeout(timerRef.current);
    const target = Number(face);
    setActiveNav(target);
    setCurrentFace(target);
  };

  // 点击侧边点数导航
  const handleNavClick = (e, face) => {
    e.preventDefault();
    resetDice();
    rollTo(face);
  };

  // 触发随机掷骰子
  const handleRandomRoll = (e) => {
    e.preventDefault();
    if (timerRef.current) clearTimeout(timerRef.current);
    setIsRolling(true);

    timerRef.current = setTimeout(() => {
      setIsRolling(false);
      rollTo(getRandomFace());
    }, ANIMATION_DURATION);
  };

  return (
    <div className="dice-container">
      {/* 点数选择导航,对应原代码ul>li>a结构 */}
      <ul>
        {Array.from({ length: SIDES }, (_, i) => i + INITIAL_SIDE).map(face => (
          <li key={face}>
            <a
              href={`#${face}`}
              className={activeNav === face ? 'active' : ''}
              onClick={(e) => handleNavClick(e, face)}
            >
              {face}
            </a>
          </li>
        ))}
      </ul>

      {/* 骰子本体,最终渲染的class、data-face属性和原jQuery版本完全一致 */}
      <div
        className={`die ${isRolling ? 'rolling' : ''}`}
        data-face={currentFace}
        onClick={handleRandomRoll}
      >
        {/* 这里放你原来骰子各个面的DOM结构即可,不用修改 */}
      </div>

      {/* 随机掷骰按钮 */}
      <button className="randomize" onClick={handleRandomRoll}>
        掷骰子
      </button>
    </div>
  );
};

export default DiceRoller;

使用说明

  • 你之前写的所有CSS样式、骰子内部的面结构完全不用调整,最终渲染出的DOM结构和jQuery版本完全一致,动画效果可以直接复用
  • 事件回调里的e.preventDefault()等价于原jQuery代码里的return false,用来阻止a标签的默认跳转行为
  • 如果你的项目用的是类组件,逻辑完全一致,只需要把useState换成this.state、useRef换成类属性、useEffect换成componentWillUnmount即可。

内容的提问来源于stack exchange,提问作者Eric Wargin

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.01 01:36:27