情景再现
需求:在Web页面中添加一个使用移动设备扫描二维码的功能,在点击按钮时显示二维码(在点击按钮二维码消失),点击非二维码区域时将其隐藏起来。
出现问题:点击按钮二维码显示之后,在点击按钮,二维码一直显示,不会消失
分析原因:React合成事件系统的委托机制,依赖事件的冒泡机制完成委派,在点击按钮时,同时触发了body上绑定的事件
出错代码:
class QrCode extends Component {
constructor(props) {
super(props);
this.handleClick = this.handleClick.bind(this);
this.handleClickQr = this.handleClickQr.bind(this);
this.state = {
active: false,
};
}
componentDidMount() {
debugger
document.body.addEventListener('click', e => {
this.setState({
active: false
});
});
// 不要将合成事件与原生事件混用
document.querySelector('.code').addEventListener('click', e => {
e.stopPropagation();
})
}
componentWillUnmount() {
document.body.removeEventListener('click');
document.querySelector('.code').removeEventListener('click');
}
handleClick() {
this.setState({
active: !this.state.active,
});
}
render() {
return (
<div className="qr-wrapper">
<button className="qr" >二维码</button>
<div
className="code"
style={{display:this.state.active ? 'block' : 'none'}}
{onClick={this.handleClickQr}
>
<img src={require('./a.jpg')} />
</div>
</div>
);
}
}
修改:不要将合成事件与原生事件混用,都改为原生事件
class QrCode extends Component {
constructor(props) {
super(props);
this.handleClick = this.handleClick.bind(this);
this.state = {
active: false,
};
}
componentDidMount() {
document.body.addEventListener('click', e => {
this.setState({
active: false
});
});
document.querySelector('.qr').addEventListener('click', e => {
this.setState({
active: !this.state.active,
});
// 必须加上阻止事件冒泡
e.stopPropagation();
})
// 不要将合成事件与原生事件混用
document.querySelector('.code').addEventListener('click', e => {
e.stopPropagation();
})
}
componentWillUnmount() {
document.body.removeEventListener('click');
document.querySelector('.code').removeEventListener('click');
document.querySelector('.qr').removeEventListener('click');
}
render() {
return (
<div className="qr-wrapper">
<button className="qr" >二维码</button>
<div
className="code"
style={{display:this.state.active ? 'block' : 'none'}}
>
<img src={require('./a.jpg')} />
</div>
</div>
);
}
}