我有一个组件,其中渲染了一些按钮。每个按钮应有其工具提示。我想在我的:hover按钮时显示工具提示。但是因为我的工具提示不仅可以包含文本,所以不能使用气球等功能,也不能仅使用CSS创建它。
这个想法是使用react-tether将我自己的Tooltip组件绑定到按钮。但是,如果我将鼠标悬停在按钮上,则会出现提示信息。因此,我想使用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>
)}
其中工具提示只是React.StatelessComponent,而Button是简单的React.PureComponent。
我通常会遇到问题,Button是JSX.Element而不是Element,因此我不能将其用作门户中的目标元素。另一件事是,我不确定在这种情况下如何使用ref以及使用id是否更好。 我愿意接受任何想法。
答案 0 :(得分:1)
我认为我编写的这种代码和平会对您有所帮助。 它不完全像工具提示那样工作,但是它显示了如何使用门户。
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;