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

Fixed Data Table中react-tippy tooltip内容事件无法触发的问题

解决react-tippy tooltip中事件无法触发的问题

我遇到过类似的情况,核心问题在于react-tippy的html选项传入的JSX并没有被React的事件系统管理——tippy内部会把这段JSX转换成静态DOM节点直接插入页面,而这些节点脱离了React的渲染流程,导致你绑定的onClick、onMouseEnter等React事件完全不会被触发。

下面给你两种可行的解决方案:

方案一:使用原生JavaScript事件绑定

在tooltip显示时,手动给内容元素添加原生事件监听,绕开React事件系统的限制:

import React from 'react';
import { Cell } from 'fixed-data-table-2';
import { Tooltip } from 'react-tippy';
import 'actionCell.scss';
const { StyleSheet, css } = require('aphrodite');

export default class ActionCell extends React.PureComponent {
  // 绑定原生事件的回调
  handleItemClick = (e) => {
    console.log('list item click:', e.target.textContent);
    // 这里可以根据点击的选项执行对应逻辑
  };

  handleItemMouseEnter = (e) => {
    console.log('list item mouse enter:', e.target.textContent);
  };

  handleItemMouseLeave = (e) => {
    console.log('list item mouse leave:', e.target.textContent);
  };

  // tooltip显示时绑定事件
  handleTooltipShow = (instance) => {
    const itemNodes = instance.popper.querySelectorAll('.actions-list__item');
    itemNodes.forEach(item => {
      // 先移除旧监听,避免重复绑定
      item.removeEventListener('click', this.handleItemClick);
      item.removeEventListener('mouseenter', this.handleItemMouseEnter);
      item.removeEventListener('mouseleave', this.handleItemMouseLeave);
      // 添加原生事件监听
      item.addEventListener('click', this.handleItemClick);
      item.addEventListener('mouseenter', this.handleItemMouseEnter);
      item.addEventListener('mouseleave', this.handleItemMouseLeave);
    });
  };

  render() {
    const { ...props } = this.props;
    return (
      <Cell {...props} className={css(styles.actionCell)} 
        onMouseEnter={() => console.log('cell mouse enter')} 
        onMouseLeave={() => console.log('cell mouse leave')}
      >
        <Tooltip 
          title="action" 
          position="bottom" 
          trigger="click" 
          animation="fade" 
          theme="light" 
          arrow 
          html={
            <ul className="actions-list">
              <li className="actions-list__item text-left">Close</li>
              <li className="actions-list__item text-left">Details</li>
            </ul>
          }
          onShow={this.handleTooltipShow}
        >
          <span>操作</span>
        </Tooltip>
      </Cell>
    );
  }
}

方案二:使用React Portal渲染tooltip内容

这种方式可以让tooltip内容完全处于React的管理之下,事件能正常触发,更符合React的开发习惯:

import React from 'react';
import { Cell } from 'fixed-data-table-2';
import { Tooltip } from 'react-tippy';
import ReactDOM from 'react-dom';
import 'actionCell.scss';
const { StyleSheet, css } = require('aphrodite');

// 单独抽离tooltip内容组件
const TooltipContent = () => {
  return (
    <ul className="actions-list">
      <li className="actions-list__item text-left" 
          onClick={() => console.log('list item click: Close')}
          onMouseEnter={() => console.log('list item mouse enter: Close')}>
        Close
      </li>
      <li className="actions-list__item text-left"
          onClick={() => console.log('list item click: Details')}
          onMouseEnter={() => console.log('list item mouse enter: Details')}>
        Details
      </li>
    </ul>
  );
};

export default class ActionCell extends React.PureComponent {
  portalContainer = null;

  handleTooltipShow = (instance) => {
    // 获取tippy的内容容器
    const contentEl = instance.popper.querySelector('.tippy-content');
    if (contentEl) {
      contentEl.innerHTML = '';
      this.portalContainer = contentEl;
      // 使用Portal渲染React组件
      ReactDOM.render(<TooltipContent />, contentEl);
    }
  };

  handleTooltipHide = () => {
    // 隐藏时卸载组件,避免内存泄漏
    if (this.portalContainer) {
      ReactDOM.unmountComponentAtNode(this.portalContainer);
      this.portalContainer = null;
    }
  };

  render() {
    const { ...props } = this.props;
    return (
      <Cell {...props} className={css(styles.actionCell)} 
        onMouseEnter={() => console.log('cell mouse enter')} 
        onMouseLeave={() => console.log('cell mouse leave')}
      >
        <Tooltip 
          title="action" 
          position="bottom" 
          trigger="click" 
          animation="fade" 
          theme="light" 
          arrow 
          html={<div></div>} {/* 先传入空容器占位 */}
          onShow={this.handleTooltipShow}
          onHide={this.handleTooltipHide}
        >
          <span>操作</span>
        </Tooltip>
      </Cell>
    );
  }
}

两种方案都能解决你的问题,方案二更贴近React的组件化思想,推荐使用。另外建议检查一下react-tippy的版本,确保依赖是最新的,避免版本兼容问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 06:46:20