javascript - 如何将 react-tether 与 react-dom createPortal 一起使用,以便能够根据它所绑定(bind)的组件来设置绑定(bind)组件的样式?

标签 javascript reactjs typescript jsx

我有一个组件,我在其中渲染了一些按钮。每个按钮都应该有它的工具提示。我想让工具提示在我 :hover 按钮时出现。但是因为我的工具提示不仅可以包含文本,所以我不能使用气球之类的东西,也不能只用 css 创建它。

我的想法是使用 react-tether 将我自己的 Tooltip 组件绑定(bind)到按钮。但是后来我必须管理,如果我将鼠标悬停在按钮上,就会出现工具提示。所以我想使用 react-portal 将工具提示移动到我的按钮组件内,这样我就可以根据其实际父级来设置工具提示的样式。

这是我已经想到的想法,但它并不像现在这样行得通。

    export const Bar: React.StatelessComponent<IBarProps> = (props) => {
    const { button1, button2} = props;

      return (
        <div>
          <TetherComponent
          ...
          >
            <Button
             ref={button1ref} //???
             ...(some props)
            >
              {button1.text}
            </Button>
            {
              createPortal(
                  <tooltip>button1.tooltipText</tooltip>,
                  button1ref)
            }
          </TetherComponent>

          <TetherComponent
          ...
          >...the same with second button
          </TetherComponent>
        </div>
    )}

其中 Tooltip 只是 React.StatelessComponent,Button 是简单的 React.PureComponent。

我经常遇到这个问题,Button 是 JSX.Element 而不是 Element,所以我不能将它用作门户中的目标元素。另一件事是,我不确定在这种情况下如何使用 ref 以及使用 id 是否更好。 我愿意接受任何想法。

最佳答案

我认为我编写的这段安静的代码会对您有所帮助。 它的工作方式与工具提示不完全相同,但它显示了如何使用门户。

import React, {Component} from 'react';
import ReactDOM from 'react-dom';
import PropTypes from "prop-types";

class TooltipButton extends Component {
    state = {
        isHovered: false
    };

    buttonRef = React.createRef();

    onMouseOver = isOver => {
        this.setState({
            isHovered: isOver
        });
    };

    render() {
        const tooltip = (
            <div>
                {this.props.tooltip}
            </div>
        );

        return (
            <div>
                <button
                    ref={this.buttonRef}
                    onMouseEnter={() => this.onMouseOver(true)}
                    onMouseLeave={() => this.onMouseOver(false)}
                >
                    {this.props.text}
                </button>
                {this.state.isHovered ?
                    ReactDOM.createPortal(tooltip, this.buttonRef.current) :
                    undefined}
            </div>
        );
    }
}

TooltipButton.propTypes = {
    text: PropTypes.string.isRequired,
    tooltip: PropTypes.string.isRequired
};

export default TooltipButton;

此示例展示了如何使用门户,但门户的目的是将某些内容(工具提示元素)添加到另一个元素(例如 document.body),而不是添加到同一元素。在这种情况下,createPortal 实际上不执行任何操作。

打开同一个房间的传送门没有任何意义:)

我认为你需要做这样的事情:

import React, {Component} from 'react';
import ReactDOM from 'react-dom';
import PropTypes from "prop-types";

class TooltipButton extends Component {
    state = {
        isHovered: false
    };

    buttonRef = React.createRef();

    constructor() {
        super();
        this.tooltipElement = document.createElement('div');
    }

    onMouseOver = isOver => {
        this.setState({
            isHovered: isOver
        });
    };

    componentDidMount() {
        document.body.appendChild(this.tooltipElement);
    }

    componentWillUnmount() {
        document.body.removeChild(this.el);
    }

    render() {
        let buttonRect;
        let tooltip;
        if (this.buttonRef.current) {
            buttonRect = this.buttonRef.current.getBoundingClientRect();
            tooltip = (
                <div style={{
                    zIndex: Number.MAX_SAFE_INTEGER,
                    position: 'absolute',
                    top: buttonRect.top,
                    left: buttonRect.right,
                    backgroundColor: 'lightgrey'
                }}>
                    {this.props.tooltip}
                </div>
            );
        }

        return (
            <div>
                <button
                    ref={this.buttonRef}
                    onMouseEnter={() => this.onMouseOver(true)}
                    onMouseLeave={() => this.onMouseOver(false)}
                >
                    {this.props.text}
                </button>
                {this.state.isHovered ?
                    ReactDOM.createPortal(tooltip, this.tooltipElement) :
                    undefined}
            </div>
        );
    }
}

TooltipButton.propTypes = {
    text: PropTypes.string.isRequired,
    tooltip: PropTypes.string.isRequired
};

export default TooltipButton;

关于javascript - 如何将 react-tether 与 react-dom createPortal 一起使用,以便能够根据它所绑定(bind)的组件来设置绑定(bind)组件的样式?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54025981/

相关文章:

javascript - JavaScript 中循环引用会导致内存泄漏吗?

reactjs - 如何在 React Konva 中为舞台或图层设置圆角

node.js - React App在本地运行,但在Heroku上崩溃并显示错误代码= H10

javascript - 为什么这些子项没有在 TS 中呈现为数组?

当我将参数设置为对象时,JavaScript 返回 TypeError

javascript - React router dom 库不适用于我的项目

javascript - 似乎无法在 javascript 中添加两个整数?

Reactjs、jest、enzyme、react-universal-component - 如何使用动态导入测试组件结构?

angular - 将鼠标事件传递给组件 onclick

javascript - 接下来如何修复错误不是 Angular 中的函数