如何防止嵌套React组件中的事件冒泡点击?

这是一个基本组件。<ul><li>都有onClick函数。我只希望在<li>上的onClick被触发,而不是<ul>。我怎样才能做到这一点呢?

我已经玩了e.preventDefault(), e.stopPropagation(),没有任何效果。

class List extends React.Component {
constructor(props) {
super(props);
}


handleClick() {
// do something
}


render() {


return (
<ul
onClick={(e) => {
console.log('parent');
this.handleClick();
}}
>
<li
onClick={(e) => {
console.log('child');
// prevent default? prevent propagation?
this.handleClick();
}}
>
</li>
</ul>
)
}
}


// => parent
// => child
183596 次浏览

我也有同样的问题。我发现stopPropagation 做了工作。我将把列表项拆分为一个单独的组件,如下所示:

class List extends React.Component {
handleClick = e => {
// do something
}


render() {
return (
<ul onClick={this.handleClick}>
<ListItem onClick={this.handleClick}>Item</ListItem>
</ul>
)
}
}


class ListItem extends React.Component {
handleClick = e => {
e.stopPropagation();  //  <------ Here is the magic
this.props.onClick();
}


render() {
return (
<li onClick={this.handleClick}>
{this.props.children}
</li>
)
}
}

React在文档中使用事件委托和单个事件监听器来处理冒泡事件,比如本例中的'click',这意味着停止传播是不可能的;当你在React中与它交互时,真实的事件已经传播了。在React的合成事件上stopPropagation是可能的,因为React在内部处理合成事件的传播。

stopPropagation: function(e){
e.stopPropagation();
e.nativeEvent.stopImmediatePropagation();
}

新的方法更简单,会节省你一些时间!只需将事件传递给原始的单击处理程序并调用preventDefault();

clickHandler(e){
e.preventDefault();
//Your functionality here
}

我有问题得到event.stopPropagation()工作。如果您也这样做,尝试将其移动到您的点击处理程序函数的顶部,这是我需要做的事情来阻止事件冒泡。示例函数:

  toggleFilter(e) {
e.stopPropagation(); // If moved to the end of the function, will not work
let target = e.target;
let i = 10; // Sanity breaker


while(true) {
if (--i === 0) { return; }
if (target.classList.contains("filter")) {
target.classList.toggle("active");
break;
}
target = target.parentNode;
}
}

这并不是100%理想,但如果在children ->儿童时尚中传递props或为此目的创建Context.Provider/Context.Consumer 只是太痛苦),并且你正在处理的是另一个库,它在你的库之前运行它自己的处理程序,你也可以尝试:

   function myHandler(e) {
e.persist();
e.nativeEvent.stopImmediatePropagation();
e.stopPropagation();
}

据我所知,event.persist方法防止对象立即被扔回React的SyntheticEvent池。因此,在React中传递的event在你到达它的时候实际上并不存在!这发生在孙辈中,因为React句柄的内部方式是首先检查父句柄上的SyntheticEvent句柄(特别是如果父句柄有回调)。

只要你没有调用persist来创建一些重要的内存来继续创建诸如onMouseMove这样的事件(并且你没有创建一些类似于Grandma's Cookies的Cookie Clicker游戏),这应该是完全没问题的!

另请注意:从偶尔阅读他们的GitHub,我们应该密切关注React的未来版本,因为他们五月最终解决了一些痛苦,因为他们似乎要在编译器/编译器中折叠React代码。

你可以通过检查事件的目标来避免事件冒泡 例如,如果你的输入嵌套在div元素中,其中有用于单击事件的处理程序,而你不想处理它,当输入被单击时,你可以将event.target传递到你的处理程序中,并检查是否应该根据target的属性执行处理程序 例如,你可以检查if (target.localName === "input") { return}.
因此,这是一种“避免”处理程序执行的方法

DOM事件的顺序:捕获vs冒泡

事件的传播有两个阶段。它们被称为“捕捉”“冒泡”

               | |                                   / \
---------------| |-----------------   ---------------| |-----------------
| element1     | |                |   | element1     | |                |
|   -----------| |-----------     |   |   -----------| |-----------     |
|   |element2  \ /          |     |   |   |element2  | |          |     |
|   -------------------------     |   |   -------------------------     |
|        Event CAPTURING          |   |        Event BUBBLING           |
-----------------------------------   -----------------------------------

捕获阶段首先发生,然后是冒泡阶段。当您使用常规DOM api注册一个事件时,默认情况下,事件将是冒泡阶段的一部分,但这可以在事件创建时指定

// CAPTURING event
button.addEventListener('click', handleClick, true)


// BUBBLING events
button.addEventListener('click', handleClick, false)
button.addEventListener('click', handleClick)

在React中,冒泡事件也是默认使用的。

// handleClick is a BUBBLING (synthetic) event
<button onClick={handleClick}></button>


// handleClick is a CAPTURING (synthetic) event
<button onClickCapture={handleClick}></button>

让我们来看看我们的handleClick回调(React):

function handleClick(e) {
// This will prevent any synthetic events from firing after this one
e.stopPropagation()
}
function handleClick(e) {
// This will set e.defaultPrevented to true
// (for all synthetic events firing after this one)
e.preventDefault()
}

一个我在这里没有看到的替代方案

如果你在所有的事件中调用e.preventDefault(),你可以检查一个事件是否已经被处理,并防止它再次被处理:

handleEvent(e) {
if (e.defaultPrevented) return  // Exits here if event has been handled
e.preventDefault()


// Perform whatever you need to here.
}

关于合成事件和本机事件的区别,请参阅React文档:https://reactjs.org/docs/events.html

这是一种简单的方法,可以防止单击事件向前移动到下一个组件,然后调用你的yourFunction。

<Button onClick={(e)=> {e.stopPropagation(); yourFunction(someParam)}}>Delete</Button>
解决这个问题的另一种方法是在子节点上设置onMouseEnter和onMouseLeave事件。(你的& lt;李比;标签) 当鼠标悬停在子进程上时,您可以设置一个特定的状态来停止父进程以执行onClick函数内容。 比如:< / p >
class List extends React.Component {
constructor(props) {
super(props)
this.state.overLi = false
}


handleClick() {
// do something
}


render() {
return (
<ul
onClick={(e) => {
if (!this.state.overLi) {
console.log("parent")
this.handleClick()
}
}}
>
<li
onClick={(e) => {
console.log("child")
// prevent default? prevent propagation?
this.handleClick()
}}
onMouseEnter={() =>
this.setState({
overLi: true,
})
}
onMouseLeave={() =>
this.setState({
overLi: false,
})}
></li>
</ul>
)
}
}

我已经搜索了很多,没有设法实现任何解决方案为我的上下文使用e.s stoppropagation ()

如果希望发生嵌套元素中的操作而不是父元素中的操作,则可以从父元素的操作处理程序中检查目标的类型,然后根据该类型执行操作,也就是说,如果目标是嵌套元素,则不执行任何操作。否则两个处理程序都将被调用。

// Handler of the parent element. Let's assume the nested element is a checkbox
function handleSingleSelection(e) {
if(e.target.type !== 'checkbox') {
// We do not do anything from the
// parent handler if the target is a checkbox ( our nested element)
// Note that the target will always be the nested element
dispatch(lineSelectionSingle({ line }))
}
}