我有一个树状结构。当我在该节点上单击鼠标右键时,将出现contextMenu,在其中可以选择选项-“添加节点”和“编辑节点”。当我单击添加节点时,应该出现引导程序模态,但它不会出现,因为在主体上,我有一个单击事件监听器,负责隐藏上下文菜单。
这是我的点击侦听器方法:
componentDidMount() {
document.body.addEventListener('click', this.handleClick.bind(this))
}
componentWillUnmount() {
document.body.removeEventListener('click', this.handleClick.bind(this))
}
我决定将我的unmount方法传递给ContextMenu组件,并在显示模式之前对其进行调用
<ContextMenu removeEventListener={this.componentWillUnmount.bind(this)} left={this.state.left} top={this.state.top}/>}
ContextMenu:
import React from 'react'
import {MyVerticallyCenteredModal} from './MyVerticallyCenteredModal'
function ContextMenu({removeEventListener, left, top}){
const [modalShow, setModalShow] = React.useState(false);
return(
<React.Fragment>
<ul className="contextMenu" style={{left: left, top: top}}>
<li onClick={() => {
removeEventListener()
setModalShow(true)
}}>Add Node</li>
<li>Edit Node</li>
</ul>
<MyVerticallyCenteredModal
show={modalShow}
onHide={() => setModalShow(false)}/>
</React.Fragment>
)
}
export default ContextMenu
不幸的是,它不起作用:(
更新:
import React, { Component } from 'react'
import {treeActions} from '../_actions'
import { connect } from 'react-redux';
import Node from './Node/Node'
import './style.css'
import ContextMenu from './ContextMenu'
class TreePage extends Component {
componentDidMount() {
//this.props.getTree()
document.body.addEventListener('click', this.handleClick.bind(this))
}
state = {activeNode: 0, showContextMenu: false, top:0, left:0}
setActiveNode(id) {
this.setState({activeNode: id})
}
handleClick() {
this.setState({showContextMenu: false})
}
handleContextMenu(event, id){
event.preventDefault()
this.setActiveNode(id)
this.setState({showContextMenu: true, left: event.clientX, top: event.clientY})
}
renderSubNodes(subNodes) {
const {activeNode} = this.state
return (
<ul>
{subNodes.map((node) => (
<React.Fragment>
<li>
<div onContextMenu={(event) => this.handleContextMenu(event, node.id)} className={activeNode===node.id?"bgSelected":""} key={node.id} onClick={() => this.setActiveNode(node.id)}>
<Node name={node.name}/>
</div>
{node.subNodes.length > 0 && this.renderSubNodes(node.subNodes)}
</li>
</React.Fragment>
))}
</ul>
);
}
render() {
//const {items} = this.props.tree;
const tree = [
{
id: 1,
name: 'node1',
subNodes: [
{
id: 4,
name: 'node1-1',
subNodes: [],
},
{
id: 5,
name: 'node1-2',
subNodes: [],
},
],
},
{
id: 2,
name: 'node2',
subNodes: [],
},
{
id: 3,
name: 'node3',
subNodes: [
{
id: 6,
name: 'node3-1',
subNodes: [
{
id: 7,
name: 'node3-1-1',
subNodes: [],
},
{
id: 8,
name: 'node3-1-2',
subNodes: [],
},
],
},
{
id: 9,
name: 'node3-2',
subNodes: [],
}
],
},
];
return(
<React.Fragment>
{this.renderSubNodes(tree)}
{this.state.showContextMenu? <ContextMenu left={this.state.left} top={this.state.top}/>:''}
</React.Fragment>
)
}
}
function mapState(state){
return state;
}
const actionCreators = {
getTree: treeActions.getTree
}
const connectedApp = connect(mapState, actionCreators)(TreePage)
export {connectedApp as TreePage}
ContextMenu:
import React from 'react'
import {MyVerticallyCenteredModal} from './MyVerticallyCenteredModal'
function ContextMenu({left, top}){
const [modalShow, setModalShow] = React.useState(false);
return(
<React.Fragment>
<ul className="contextMenu" style={{left: left, top: top}}>
<li onClick={(event) => {
event.stopPropagation()
setModalShow(true)
}}>Add Node</li>
<li>Edit Node</li>
</ul>
<MyVerticallyCenteredModal
show={modalShow}
onHide={() => setModalShow(false)}/>
</React.Fragment>
)
}
export default ContextMenu
HTML DOM API具有称为“事件冒泡”的概念。简单来说,就是单击节点时。该事件一直沿父树向上冒泡。这导致触发您身上的onClick。
使用event.stopPropagation()
可以停止此行为。这将阻止事件冒泡。
您的示例将onClick函数更改为:
(event) => {
event.stopPropagation()
setModalShow(true)
}
这样,您就不必在主体节点上卸载事件处理程序。