问题
This seems to work perfectly in Chrome and Edge. I have a tooltip that needs to pop up onClick of the button, and then disappear onBlur. For some reason the onBlur event does not fire at all on Safari or Firefox.
I've tried logging to the console in handleBlur and it does not get that far, it is as if onBlur does not exist in this context.
class Tooltip extends Component {
componentWillUnmount() {
this.closeActiveTooltip();
}
handleKeyPress = (event) => {
if (event.keyCode === 27) { // Esc key
this.closeActiveTooltip();
}
}
handleBlur = () => {
if (this.props.activeTooltip === this.props.name) {
// setTimeout is for link click
setTimeout(this.closeActiveTooltip, 100);
}
}
closeActiveTooltip = () => {
const { activeTooltip, closeTooltip } = this.props;
if (activeTooltip) {
closeTooltip(activeTooltip);
}
}
render() {
const {
isOpen,
text,
link,
position,
} = this.props;
const popupClassName = getClassNameFor(s, 'popup', `${isOpen && 'open'} ${position}`);
const linkElement = (
<div className={s.link}>
<a
href={link}
target="_blank"
rel="noopener noreferrer"
>
More info here
</a>
</div>
);
return (
<button
type="button"
className={s.root}
onClick={this.props.toggleTooltip}
onBlur={this.handleBlur}
onKeyDown={this.handleKeyPress}
>
<svg className={s.icon}>
<use xlinkHref="#more-info" />
</svg>
<div className={popupClassName}>
{text}
{link && linkElement}
</div>
</button>
);
}
}
回答1:
All I know is that I could never get an element (most likely an <input />
) focused on mount with React, probably because of render()
s, so I use setTimeout(() => input.focus(), 0)
to make it async. So, it seems there are issues with focus handling...
A simple workaround would be:
<button
onClick={this.handleAction}
onMouseDown={this.handleFocus}
onMouseUp={this.handleBlur} />
But when user release the mouse button out of the button, you'll never trigger the onMouseUp
.
A better workaround consists in simulating a click out:
class Tooltip extends Component {
componentDidMount() {
document.body.addEventListener('click', this.handleClickOut, false);
}
componentWillUnmount() {
document.body.removeEventListener('click', this.handleClickOut, false);
}
handleClickOut = event => {
if(event.target != this.refs.btn) { // Actually more complicated, event.target can be a child of button (icon, span, etc)
this.handleBlur();
}
}
handleBlur() {}
render() {
return (
<button
ref='btn'
type="button"
>
{text}
</button>
);
}
}
possibly with a component that wraps your button
<ClickOut onClickOut={this.handleBlur}>
<button
onClick={this.handleAction}
onMouseDown={this.handleFocus} />
</ClickOut>
Any time you click on your document, if target
is not <button />
or one of its child nodes, trigger the click out pseudo event
来源:https://stackoverflow.com/questions/44431931/react-redux-onblur-event-not-firing-in-safari-and-firefox