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

React实现鼠标悬停段落指定词语时图片跟随光标移动的开发问题

解决方案

调整组件逻辑后可支持指定段落内的关键词绑定对应悬停图片,具体实现如下:

核心思路

  • 新增hoverKeywordMap属性,接收「关键词: 对应图片地址」的映射配置,支持不同关键词触发不同图片
  • 新增文本拆分逻辑,将传入的段落文本切割为普通文本片段和可触发悬停的关键词节点,关键词用<span>标签包裹并绑定鼠标事件
  • 移除性能冗余的setInterval定时器,直接在鼠标移动事件中更新图片坐标
  • 使用React Ref操作DOM节点,避免全局选择器的冲突问题

完整修改代码

JS代码

import React from "react";
import "../../index.css";
import codingJoke from "../../images/codingJoke.png";
import "./raisedTextContainer.css";

export default class RaisedTextContainer extends React.Component {
  constructor(props) {
    super(props);
    this.state = { 
      mouseOver: false,
      activeImage: null // 当前要显示的悬停图片
    };
    this.imageRef = React.createRef(); // 图片容器ref
    this._onMouseMove = this._onMouseMove.bind(this);
    this.renderText = this.renderText.bind(this);
  }

  // 拆分渲染段落文本,把关键词替换为可触发悬停的节点
  renderText() {
    const { paragraph, hoverKeywordMap = {} } = this.props;
    const keywords = Object.keys(hoverKeywordMap);
    // 没有配置关键词直接返回原文本
    if (keywords.length === 0) return paragraph;
    // 构建匹配所有关键词的正则
    const matchRegex = new RegExp(`(${keywords.join('|')})`, 'g');
    const textFragments = paragraph.split(matchRegex);

    return textFragments.map((fragment, index) => {
      // 匹配到关键词则返回带事件的span
      if (keywords.includes(fragment)) {
        return (
          <span
            key={index}
            className="hover-trigger"
            data-img-url={hoverKeywordMap[fragment]}
            onMouseEnter={(e) => {
              this.setState({
                mouseOver: true,
                activeImage: e.target.dataset.imgUrl
              })
            }}
            onMouseLeave={() => {
              this.setState({
                mouseOver: false,
                activeImage: null
              })
            }}
            onMouseMove={this._onMouseMove}
          >
            {fragment}
          </span>
        )
      }
      // 普通文本直接返回
      return <span key={index}>{fragment}</span>
    })
  }

  _onMouseMove(e) {
    // 未悬停在关键词上或图片未挂载直接返回
    if (!this.state.mouseOver || !this.imageRef.current) return;
    const offsetX = 15; // 图片距离光标的水平偏移,避免挡住光标
    const offsetY = 15; // 图片距离光标的垂直偏移
    this.imageRef.current.style.left = `${e.clientX + offsetX}px`;
    this.imageRef.current.style.top = `${e.clientY + offsetY}px`;
  }

  render() {
    return (
      <div className="grid-item rounded raised">
        <div
          style={{ zIndex: 2 }}
          className="photo-hover"
        >
          <h3>test Image hover thing</h3>
        </div>
        {/* 悬停图片容器 */}
        <div 
          ref={this.imageRef}
          className="hoverimage"
          style={{ display: this.state.mouseOver ? 'block' : 'none' }}
        >
          <img src={this.state.activeImage} alt="" />
        </div>
        {/* 渲染处理后的段落文本 */}
        <p>{this.renderText()}</p>
      </div>
    );
  }
}

CSS代码

.hoverimage {
    position: absolute;
    pointer-events: none;
    z-index: 999; /* 确保图片在最上层不会被遮挡 */
    border-radius: 4px;
    box-shadow: 0 2px 12px rgba(0,0,0,0.15);
}
/* 可触发悬停的关键词样式,可自定义调整 */
.hover-trigger {
    color: #165DFF;
    border-bottom: 1px dashed #165DFF;
    cursor: pointer;
}

组件使用示例

<RaisedTextContainer
  paragraph="我今天写了个搞笑的codingJoke,调试了半天终于跑通了"
  hoverKeywordMap={{
    "codingJoke": codingJoke
  }}
/>

注意事项

  • 如果关键词包含正则特殊字符,需要提前做转义处理避免匹配报错
  • 图片的偏移量可根据实际交互需求自行调整
  • 如果需要支持同一个关键词绑定不同图片,可扩展逻辑给关键词加唯一标识处理

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.06 09:48:02