如何避免在拖动子元素时同时拖动父级元素?

3

我已经在我的React应用程序导航栏中添加了一个功能,使用户可以拖动项目并更改位置。(运作良好!)

现在我正在尝试递归地渲染导航树,以便可以拖动和替换内部导航(不重新设置父级关系)。

递归渲染的工作正常,但问题是拖动内部子项会导致整个父节点被拖动。

NodeWrapper.js

export class NodeWrapper extends Component {
  public render() {
    return (
      <DragList onItemMoved={this.props.onItemMoved}>
        {this.props.navItems
          .map((component, index) => (
            <Node key={`node-${index}`} {...component}/>
          ))}
      </DragList>
    );
  }
}

Node.js:

public render() {
 return (
  <div>
    <span>{this.props.label}</span>
    {this.props.childNodes && (
      <NodeWrapper navItems={this.props.childNodes} />
    )}
  </div>
 );
}

注意,DragList组件非常庞大,我认为它与问题无关,如果需要,我会添加。基本上,它使用事件处理程序渲染一个子级列表,并允许拖动它们。
我尝试在拖动事件处理程序中添加event.stopPropagation(),但仍然会捕获并拖动整个父节点。
我该如何在所有级别之间执行拖动?

6
能否为我们创建一个小型的codesandbox项目,以便我们可以进行尝试?目前的情况下我认为无法解答,而且我相信没有人想要花时间先构建一个可工作的演示。 - Swiffy
3
你能展示一下 DragList 的文档吗?HTML 元素有一个 draggable 属性,可以设置为 false 来禁用拖拽。 - Nice Books
1
event.stopPropagation 似乎是解决问题的方法,但如何以及在哪里使用它可能是关键。您能否添加 DragList 代码以进行检查? - Tadeo
2个回答

0

在每个事件监听器上的内部子元素上使用e.stopPropagation(),例如onDrag和onClick。

例如:

<div class="wraper">
  <div class="inner" onDrag={(e)=>{e.stopPropagation();//do other sttuf}}></div>
</div>

在拖动的内部子元素事件处理程序中,只需使用event.stopPropagation()即可...

我无法看到您的实现以确定您如何使用拖动事件。但我猜测您使用onItemMoved属性并将其值传递给拖动处理程序,因此请尝试以下操作:

onItemMoved={(e)=> {e.stopPropagation();this.props.onItemMoved()}}

0
为了在不影响整个父节点的情况下实现导航树各级别的拖拽功能,您应该考虑实现递归的拖放机制。您在使用event.stopPropagation()方面已经走在了正确的轨道上,但是重要的是要有效地使用它。
以下是您的代码的修改版本,可以处理导航树内各级别的拖拽操作:

NodeWrapper.js:

import React, { Component } from "react";
import DragList from "./DragList"; // Import your DragList component

class NodeWrapper extends Component {
  render() {
    return (
      <DragList onItemMoved={this.props.onItemMoved}>
        {this.props.navItems.map((component, index) => (
          <Node key={`node-${index}`} {...component} />
        )}
      </DragList>
    );
  }
}

export default NodeWrapper;

Node.js:

import React, { Component } from "react";

class Node extends Component {
  onDragStart = (e) => {
    // Use the onDragStart event to prevent dragging propagation
    e.stopPropagation();
  };

  render() {
    return (
      <div>
        <span
          draggable={true}
          onDragStart={this.onDragStart}
        >
          {this.props.label}
        </span>
        {this.props.childNodes && (
          <NodeWrapper navItems={this.props.childNodes} onItemMoved={this.props.onItemMoved} />
        )}
      </div>
    );
  }
}

export default Node;

要注意的要点:
1. 在 `Node` 组件中,我们在 `` 元素上添加了 `draggable` 属性,使其可拖动。 2. 我们在 `` 元素上添加了 `onDragStart` 事件处理程序。该事件处理程序阻止了拖动事件进一步向上 DOM 树传播,有效地阻止了拖动影响整个父节点。 3. 在使用 `NodeWrapper` 渲染子节点时,我们将 `onItemMoved` 函数传递下去,以便在所有层级上都可以使用拖放功能。
通过这种方法,您应该能够在导航树中的任何层级拖动元素,而不会影响整个父节点。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接