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

实现鼠标跟随眼睛动画时getBoundingClientRect空值错误求助

解决React中人脸眼睛跟随鼠标动画的Uncaught TypeError问题

我参考视频实现人脸眼睛跟随鼠标移动的动画,自定义为1张基底图加1组眼睛,但控制台出现Uncaught TypeError: Cannot read properties of null (reading 'getBoundingClientRect')错误,请问原因及解决方法?

原代码

import React from "react";
import "./MovingFounder.css";

class MovingFounder extends React.Component {
    render() {
        document.addEventListener("mousemove", (e) => {
            const mouseX = e.clientX;
            const mouseY = e.clientY;

            const anchor = document.getElementById('anchor');
            const rekt = anchor.getBoundingClientRect();
            
            const anchorX = rekt.left + rekt.width / 2;
            const anchorY = rekt.top + rekt.height / 2;
            const angleDeg = angle(mouseX, mouseY, anchorX, anchorY);

            console.log(angleDeg);

            const eyes = document.querySelector(".founder-eyes");
            eyes.forEach((eye) => {
                eye.style.transform = `rotate(${angleDeg}deg)`;
            })
        });

        function angle(cx, cy, ex, ey) {
            const dy = ey - cy;
            const dx = ex - cx;
            const rad = Math.atan2(dy, dx);
            const deg = rad * (180 / Math.PI);
            return deg;

        }

        return (
            <div class="founder-moving">
                <img class="anchor" src="./images/noeyes-founder.png" alt="founder body" />
                <div>
                    <img class="founder-eyes" src="./images/founder-eyes.png" alt="founder eyes" />
                </div>
            </div>
        );
    }
}

export default MovingFounder;

错误原因

  • DOM元素匹配失败:你用getById('anchor')查找元素,但基底图标签用的是class="anchor"而非id="anchor",导致anchor变量为null,调用getBoundingClientRect()直接报错。
  • 事件绑定时机错误:在render()里绑定mousemove事件,每次组件渲染都会重复绑定,且可能在DOM未完全挂载时触发事件,进一步导致元素获取失败。
  • 元素遍历逻辑错误:querySelector(".founder-eyes")仅返回第一个匹配元素,不是数组,无法用forEach遍历,会触发额外错误。
  • React语法错误:JSX中需用className代替class,否则React无法正确解析类名。

解决方法

  1. 修正DOM选择器:给基底图添加id="anchor",或改用querySelector(".anchor")匹配类名。
  2. 规范事件绑定:在componentDidMount中绑定事件,componentWillUnmount中解绑,避免重复绑定和内存泄漏。
  3. 使用React Refs:用React内置的refs获取DOM元素,比原生DOM查询更可靠,符合React数据流规范。
  4. 修正遍历逻辑:单组眼睛直接操作元素即可;多组眼睛改用querySelectorAll(".founder-eyes")获取元素列表。
  5. 修复JSX语法:将所有class替换为className。

修正后的代码

import React from "react";
import "./MovingFounder.css";

class MovingFounder extends React.Component {
  constructor(props) {
    super(props);
    // 创建refs绑定DOM元素
    this.anchorRef = React.createRef();
    this.eyeRef = React.createRef();
  }

  componentDidMount() {
    // 组件挂载完成后绑定鼠标事件
    document.addEventListener("mousemove", this.handleMouseMove);
  }

  componentWillUnmount() {
    // 组件卸载前解绑事件,避免内存泄漏
    document.removeEventListener("mousemove", this.handleMouseMove);
  }

  handleMouseMove = (e) => {
    const mouseX = e.clientX;
    const mouseY = e.clientY;

    // 确保元素存在再执行后续逻辑
    const anchor = this.anchorRef.current;
    if (!anchor) return;

    const rekt = anchor.getBoundingClientRect();
    const anchorX = rekt.left + rekt.width / 2;
    const anchorY = rekt.top + rekt.height / 2;
    const angleDeg = this.angle(mouseX, mouseY, anchorX, anchorY);

    // 设置眼睛旋转角度
    const eye = this.eyeRef.current;
    if (eye) {
      eye.style.transform = `rotate(${angleDeg}deg)`;
    }
  };

  angle(cx, cy, ex, ey) {
    const dy = ey - cy;
    const dx = ex - cx;
    const rad = Math.atan2(dy, dx);
    const deg = rad * (180 / Math.PI);
    return deg;
  }

  render() {
    return (
      <div className="founder-moving">
        <img 
          ref={this.anchorRef} 
          className="anchor" 
          src="./images/noeyes-founder.png" 
          alt="founder body" 
        />
        <div>
          <img 
            ref={this.eyeRef} 
            className="founder-eyes" 
            src="./images/founder-eyes.png" 
            alt="founder eyes" 
          />
        </div>
      </div>
    );
  }
}

export default MovingFounder;

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.30 12:59:14