React 组件在 Firefox 和 Chrome 中的行为不同

React component behaves differently in Firefox and Chrome

我编写了一个 React 组件 Tooltipable,它能够包装另一个组件并为其显示工具提示。

它在 Firefox 中运行良好。但是,在 Chrome - 有时 - 当元素悬停在其上时,工具提示显示不一致。

有人可以解释这种行为并建议如何纠正吗?我相信它与 React 并没有真正的关系,只是我解决问题的方式 and/or 这两个浏览器呈现内容的方式。

这是一个 CodePen:

https://codepen.io/barciewicz/pen/MWpNJoy?editors=1000

这是一个工作示例。

我做了以下事情:

  1. 已将 mouseover 替换为 mousemove
  2. 已将 mouseout 替换为 mouseleave
  3. 固定列表标记(li 应该是 ul 的直接子代。您可以避免将列表与 Flexbox 或其他技术一起使用,它应该仍然有效)。
  4. 我刚刚在光标和工具提示之间添加了一些 space(我添加了 5px,但 1px 也应该可以解决问题)。如果您不这样做,每次出现工具提示时,mouseleave 事件都会在文本元素上触发(产生您注意到的故障效果)。

const Tooltip = ({x, y, content, visible}) => {
    const style = {
        position: 'fixed',
        left: x + 'px',
        top: y + 'px',
        background: 'black',
        color: 'white',
        padding: '.5%'
    };
    const tooltip = <span style={style}>{content}</span>;
    return visible ? tooltip : null;
};

const Tooltipable = ({component, tooltipContent}) => {
    const [tooltipXy, setTooltipXy] = React.useState({x: 0, y: 0});
    const [tooltipVisible, setTooltipVisible] = React.useState(false);

    const handleMouseOver = (e) => {
        setTooltipXy({x: e.clientX + 5, y: e.clientY + 5});
        setTooltipVisible(true);
    };

    const handleMouseOut = () => {
        setTooltipVisible(false);
    };

    return (
        <li>
            <span
                style={{background: 'pink'}}
                onMouseLeave={handleMouseOut}
                onMouseMove={handleMouseOver}>
                {component}
            </span>
            <Tooltip
                x={tooltipXy.x}
                y={tooltipXy.y}
                content={tooltipContent}
                visible={tooltipVisible}
            />
        </li>
    );
};

const Todos = ({todos}) => (
    <ul>
        {todos.map((todo, index) => {
            const component = (
                <span style={{background: 'powderblue', display: 'inline'}}>
                    {todo.text}
                </span>
            );
            return (
                <Tooltipable
                    key={index}
                    component={component}
                    tooltipContent={'Created ' + todo.createdOn}
                />
            );
        })}
    </ul>
);

const App = () => {
    const todos = [
        {text: 'clean car', createdOn: 'yesterday'},
        {text: 'fix windows', createdOn: 'two days ago'},
        {text: 'go shopping', createdOn: 'today'},
        {text: 'meet family', createdOn: 'five days ago'},
        {text: 'clean car', createdOn: 'yesterday'},
        {text: 'fix windows', createdOn: 'two days ago'},
        {text: 'go shopping', createdOn: 'today'},
        {text: 'meet family', createdOn: 'five days ago'},
        {text: 'clean car', createdOn: 'yesterday'},
        {text: 'fix windows', createdOn: 'two days ago'},
        {text: 'go shopping', createdOn: 'today'},
        {text: 'meet family', createdOn: 'five days ago'},
        {text: 'clean car', createdOn: 'yesterday'},
        {text: 'fix windows', createdOn: 'two days ago'},
        {text: 'go shopping', createdOn: 'today'},
        {text: 'meet family', createdOn: 'five days ago'}
    ];
    return <Todos todos={todos} />;
};

ReactDOM.render(<App />, document.getElementById('root'));
<!DOCTYPE html>
<html>

<head>

  <script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.2/umd/react.production.min.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.2/umd/react-dom.production.min.js"></script>

</head>
  
<body>
  <div id="root">
</body>

</html>