我正在使用React Digraph创建一个界面,用户可以在其中创建和编辑状态机。该界面有些可用(至少在通过键盘快捷键创建或删除节点方面),但是我需要更新该界面本身,以便用户只能使用鼠标来执行此操作。为此,我想到了以下界面:
就代码而言,这非常容易。关于API,我只需要重写方法renderNode
,并使用foreignObject
元素将HTML插入到API使用的SVG上:
public renderNode = (nodeRef: any, data: any, id: string, selected: boolean, hovered: boolean) => {
const positioning = data.type === 'required' ? styles.required : styles.optional;
return (
<g className={`shape`}>
{!selected ? null : (
<foreignObject x="-77" y="-77" width="154" height="77" xmlnsXlink="http://www.w3.org/1999/xlink">
<i className={`fas fa-edit ${styles.btn} ${positioning} ${styles.edit}`} />
<i
className={`fas fa-minus-square ${styles.btn} ${positioning} ${styles.delete}`}
onClick={() => {
console.log('onClick');
this.deleteNode(id);
}}
/>
</foreignObject>
)}
<use
className={`node ${hovered ? 'hovered' : ''} ${selected ? 'selected' : ''}`}
x="-77"
y="-77"
width="154"
height="154"
xlinkHref={`#${data.type}`}
>
<svg viewBox="-27 0 154 154" id={data.type} width="154" height="154">
<rect transform="translate(50) rotate(45)" width="109" height="109" />
</svg>
</use>
</g>
);
};
现在,一切都应按计划进行,但是由于某些原因,onClick
事件没有被捕获。没有console.log显示,也没有调用deleteNode
函数。
我正在使用:
"react": "^16.6.1",
"react-digraph": "^6.0.0",
Google Chrome Version 72.0.3626.119 (Official Build) (64-bit)
知道为什么会这样吗?
谢谢。
修改:
在James Delaney的建议之后,我尝试向所有可用节点添加引用以及事件监听器。由于我可能会从后端获取计算机的信息,因此无法静态创建所有引用。因此,我尝试在获取节点后在componentDidMount
上创建“引用列表”,并在找到的所有节点上调用addEventListener
方法,将事件侦听器添加到此列表中,并在出现以下情况时连接引用节点被渲染。实际上,这是componentDidMount
:
public componentDidMount(): void {
const { machine } = this.props;
this.setState({ graph: machine ? stateMachineToGraph(machine) : initialGraph }, () => {
this.state.graph.nodes.forEach(node => {
const del = `${node.id}delete`,
edit = `${node.id}edit`;
this[del].addEventListener('click', this.deleteNode(node.id));
this[edit].addEventListener('click', this.editNode(node.id));
});
});
}
这就是前面提到的foreignObject
:
<foreignObject x="-77" y="-77" width="154" height="77" xmlnsXlink="http://www.w3.org/1999/xlink">
<i
ref={edit => (this[`${id}edit`] = edit)}
className={`fas fa-edit ${styles.btn} ${positioning} ${styles.edit}`}
/>
<i
ref={del => (this[`${id}delete`] = del)}
className={`fas fa-minus-square ${styles.btn} ${positioning} ${styles.delete}`}
/>
</foreignObject>
不幸的是,这不起作用,并且我尝试使用显式列表或静态使用引用(出于测试目的)遍历此解决方案。没有进展。
编辑2 :
考虑到上面可能的解决方案,我重复了一些操作,并且仅在呈现节点时才添加事件监听器。这样,renderNode
方法就变成了这样:
public renderNode = (nodeRef: any, data: any, id: string, selected: boolean, hovered: boolean) => {
console.log(id);
if (this[`${id}edit`] && this[`${id}delete`]) {
this[`${id}edit`].addEventListener('click', this.editNode(id));
this[`${id}delete`].addEventListener('click', this.deleteNode(id));
}
const positioning = data.type === 'required' ? styles.required : styles.optional;
...
现在,我不测试特定节点的事件侦听器是否已存在,我将进一步进行测试。对于此实现,我最终可以删除节点,但是它无法识别出'click'事件。我只是将鼠标悬停在节点上,并触发该事件(以及“ edit”事件),然后删除该节点。为什么会这样?
谢谢。
答案 0 :(得分:1)
例如:
componentDidMount() {
this.ref.addEventListener('click', this.deleteNode(id));
}
componentWillUnmount(){
this.ref.removeEventListener('click', this.deleteNode(id));
}
}
我不确定这是否是解决方案,但是您可以尝试。