React项目场景:点击document任意节点关闭弹层
update: 2017-10-23
我们常常会遇到这样一个场景:打开一个fix的弹层,需要在用户点击除了它本身以外的任意位置时,关闭弹层。 这样的场景在日常前端的开发中太常见了,这里也不再阐述平常我们用原生js来实现的具体方法,主要讲述下如果是在React项目中遇到这种情况的处理方法。
rc-util
rc-util是一个专为React组件提供一些通用工具的插件,我们可以通过rc-util的Dom模块的一系列函数来操作dom。
1.引用rc-util中需要用到的模块,以及绑定节点需要用到的findDOMNode方法。
import addEventBodyListener from 'rc-util/lib/Dom/addEventListener';
import contains from 'rc-util/lib/Dom/contains';
import { findDOMNode } from 'react-dom';
2.通过react的ref绑定需要除外的指定区域的dom节点,方法详见react文档,这里不再赘述。通过一个组件内部的state来控制该组件的显示隐藏。
<TimeSelect ref="timemodal" visible={this.state.isShowTimeSelect} />
3.在组件的componentDidUpdate添加监听事件,监听document元素的点击事件。
componentDidUpdate() {
if (this.state.isShowTimeSelect) {
this.clickOutsideHandle = addEventBodyListener(document, 'mousedown', this.onDocumentClick.bind(this))
return
}
}
定义document元素的点击事件:获取指定区域节点,与当前点击的节点进行比较,如果当前点击的节点不是指定区域的节点,则通过state来隐藏组件,达到点击document任意节点(除指定区域外)关闭弹层的效果。
onDocumentClick(e) {
let timemodal = findDOMNode(this.refs.timemodal)
if (!contains(timemodal, e.target)) {
this.setState({
isShowTimeSelect: false
})
}
}
contains:检查node是否为root或root的子元素。
(root: HTMLElement, node: HTMLElement): boolean
Check if node is equal to root or in the subtree of root.
4.移除监听事件:在组件的componentWillUnmount和componentDidUpdate都需要移除监听事件。
componentDidUpdate() {
if (this.clickOutsideHandle) {
this.clickOutsideHandle.remove()
this.clickOutsideHandle = null
}
}
componentWillUnmount() {
if (this.clickOutsideHandle) {
this.clickOutsideHandle.remove()
this.clickOutsideHandle = null
}
}
以上,完成在React项目中实现点击document任意节点(除指定区域外)关闭弹层的效果。