Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/379.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript SVG foreignObject未捕获onClick事件(ReactJS)_Javascript_Reactjs_Events_Svg - Fatal编程技术网

Javascript SVG foreignObject未捕获onClick事件(ReactJS)

Javascript SVG foreignObject未捕获onClick事件(ReactJS),javascript,reactjs,events,svg,Javascript,Reactjs,Events,Svg,我使用创建一个界面,用户可以在其中创建和编辑状态机。界面在某种程度上是可用的(至少在通过键盘快捷键创建或删除节点方面),但我需要更新界面本身,以便用户只需使用鼠标即可完成此操作。为此,我设想了以下界面: 就代码而言,这相当简单。关于API,我只需重写方法renderNode,并使用foreignObject元素将HTML插入API使用的SVG中: public renderNode = (nodeRef: any, data: any, id: string, selected: boolea

我使用创建一个界面,用户可以在其中创建和编辑状态机。界面在某种程度上是可用的(至少在通过键盘快捷键创建或删除节点方面),但我需要更新界面本身,以便用户只需使用鼠标即可完成此操作。为此,我设想了以下界面:

就代码而言,这相当简单。关于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>
    );
  };
知道为什么会这样吗

提前谢谢

编辑
根据James Delaney的建议,我尝试向所有可用节点添加引用,并随后添加事件侦听器。因为我可能从后端获取机器的信息,所以我不能静态地创建所有引用。因此,在获取节点后,我尝试在
componentDidMount
上创建一个“引用列表”,并在找到的所有节点上调用
addEventListener
方法,将事件侦听器添加到此列表中,并在呈现节点时连接引用。实际上,这是
组件didmount

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 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>
现在我不测试特定节点的事件侦听器是否已经存在,我将进一步进行测试。对于这个实现,我最终可以删除节点,但它无法识别“click”事件。我只需将鼠标悬停在一个节点上,事件就会被触发(与“编辑”事件一起),节点就会被删除。为什么会这样

谢谢。

  • 尝试在svg元素上放置ref
  • 在componentDidMount上,将click事件侦听器添加到引用
  • 在componentWillUnmount中删除事件侦听器
例如:

componentDidMount() {
    this.ref.addEventListener('click', this.deleteNode(id));
}

componentWillUnmount(){
    this.ref.removeEventListener('click', this.deleteNode(id));
}
}


我不确定这是解决方案,但你可以试试

可以粘贴deleteNode函数的代码吗?当然可以。但是,我无法测试它,因为正如我所说的,它没有被调用:public deleteNode=id=>{const{graph}=this.state;graph.nodes.splice(0,1);graph.nodes=[…this.state.graph.nodes.filter(node=>node.id!==id)];this.setState({graph,});};我希望这能奏效,但不幸的是没有。看起来图形最初并没有呈现,因此每当我向引用添加一个事件侦听器时,它都是未定义的。。。不幸的是,我还没有找到一种方法来实现这一点,但我将通过这次尝试来更新主要帖子。谢谢你的意见。
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;
...
componentDidMount() {
    this.ref.addEventListener('click', this.deleteNode(id));
}

componentWillUnmount(){
    this.ref.removeEventListener('click', this.deleteNode(id));
}