如何在React Native中阻止父级点击事件?

19

onParentClick = () => {
  console.log('Parent is triggered');
}

onChildClick = (event) => {
  event.stopPropagation();
  console.log('Child is triggered');
}
<TouchableWithoutFeedback onPress={()=> this.onParentClick()}>
  <View>
    <Text>How to prevent parent click event</Text>
    <TouchableOpacity onPress={(event)=> this.onChildClick(event)}>
      <Text> Click Me </Text>
    </TouchableOpacity>
  </View>
</TouchableWithoutFeedback>
<!-- edit description:- there was this end curly brace missing in above,
 however the snippet will not run because the language js will not 
support it and language html will not be able to format it correctly or run it.
(need to run the snippet on the react native environment like code-pen)  -->

期望结果:点击"点击我"后,应调用onChildClick()函数

问题:点击"点击我"后,却调用了onParentClick()函数。

当点击父元素时,得到的结果为"父元素被触发",并且完全正常。

但是当点击子元素时,得到的结果却仍然是"父元素被触发"。

我猜测onChildClick()函数没有被触发。


可能是React - carousel的重复问题。 - Keith
1
请注意,OP正在使用React Native,stopPropagation是一个DOM方法。我不使用React Native,但从我所知道的来看,它仍然包含currentTarget和target,因此使用上面重复的React-carousel最有可能是OP想要的。 - Keith
对于父视图,请使用简单的<View>并使用pointerEvents='box-none'属性。 - Olegdater
9个回答

24

虽然这是一个旧的问题,但我遇到了同样的问题,在我这种情况下,问题是:

import {TouchableOpacity} from 'react-native';
import {TouchableWithoutFeedback} from 'react-native-gesture-handler';

由于 eslint 的自动建议,发生了这种奇怪的导入。不知何故,这些库之间不能很好地配合,所以我将上面的代码更改为:

这个奇怪的导入是因为 eslint 的自动建议而发生的。由于某种原因,这些库彼此之间不兼容,因此我对上面的代码进行了修改:

import {TouchableOpacity, TouchableWithoutFeedback} from 'react-native';

14
这是我第725次从react-native-gesture-handler导入react native组件,仍然遇到了问题。 - guenis
2
Saviour!! - Apoorva Verma
哦,天啊...昨天我花了一个多小时才弄清楚为什么我的TouchableOpacity忽略了width: '100%'。原来是因为这个导入。谢谢! - Episodex
谢谢!我在使用styled-components时遇到了类似的情况。解决方法要么是从react-native导入TouchableOpacity,要么是在定义样式组件时使用来自react-native-gesture-handlerTouchableOpacity。例如:import {TouchableOpacity} from 'react-native-gesture-handler',然后const Container = styled(TouchableOpacity) - myrs

4

同样的问题。onClildClick() 函数没有被触发。 - Shobika Babu
@ShobikaBabu 你需要添加 onPress 属性,例如 <View onPress={e => e.stopPropagation()}>。 - Dror Bar

3
你需要在某个地方“吞掉”点击事件。可以在外部的TouchableWithoutFeedback中这样做(例如,将onPress={()=> this.onParentClick()}更改为onPress={(e) => e.preventDefault()}),或者你可以像下面这样将TouchableOpacity包裹在另一个触摸处理程序中。
<TouchableWithoutFeedback onPress={()=> this.onParentClick()}>
  <View>
    <Text>How to prevent parent click event</Text>
    <TouchableWithoutFeedback onPress={(e) => e.preventDefault()}
      <TouchableOpacity onPress={(event)=> this.onChildClick(event)>
        <Text> Click Me </Text>
      </TouchableOpacity>
    </TouchableWithoutFeedback>
  </View>
</TouchableWithoutFeedback>

3
您可以直接将父视图的pointerEvents属性设置为“box-none”。这样做之后,父视图将不会响应触摸事件,但其子视图仍然可以被点击。
  <TouchableWithoutFeedback
      pointerEvents={'box-none'}
  >
      <TouchableWithoutFeedback
          onPress={()=>{
              //onPress here will work
          }}
      />
  </TouchableWithoutFeedback>

1
你需要使用onTouchEnd而不是press。
这是最简单的答案:
在希望停止传播的内部视图上使用此选项。
onTouchEnd={(e) => {
   e.stopPropagation()
}}

1
您描述的行为符合预期。这是因为TouchableOpacityTouchableWithoutFeedback的子组件,因此点击事件会向上冒泡,触发TouchableWithoutFeedback的点击事件。要解决此问题,可以调用event.stopPropagation()方法,阻止事件冒泡。

类似以下代码应该可以解决问题。

onChildClick = (event)=>{ //在此处执行逻辑 event.stopPropagation(); }


onChildClick()函数没有被触发。它总是触发onParentClick()。 - Shobika Babu

0
一个触发器方法:
const childPresses = {}
if(canChildPress) {
  childPresses.onPress = (event) => {this.onChildClick(event)}
}

return <TouchableWithoutFeedback onPress={()=> this.onParentClick()}>
  <View>
    <Text>How to prevent parent click event</Text>
    <TouchableOpacity {...childPresses} >
      <Text> Click Me </Text>
    </TouchableOpacity>
  </View>
</TouchableWithoutFeedback>

0

我曾经遇到过类似的问题,后来通过使用zIndex解决了它,不仅帮助我捕捉到了子组件的onPress事件,还能够同时响应父组件的onPress事件,这样我就能在一个单独的组件上执行两个不同的操作。


我们应该将zIndex添加到子元素还是父元素? - Shobika Babu
我没有做这件事。 - Ammar Tariq

0

使用gesture handler中的TouchableOpacity

import { TouchableOpacity } from "react-native-gesture-handler";

那么,改用 containerStyle 样式。

 <TouchableOpacity onPress={props.onPress} containerStyle={styles.container}>

现在一切应该看起来很好...


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