-
Notifications
You must be signed in to change notification settings - Fork 21
React Native 中 Touchable* 组件事件捕获问题
王大根 edited this page Aug 28, 2019
·
5 revisions
RN 中 Touchable*
组件内部元素的触摸事件会被 Touchable*
组件捕获。这个是符合预期的。但是如果 Touchable*
组件内部嵌套一个 ScrollView
组件,会导致 ScrollView
组件滚动异常(卡顿)。
这个问题最初是同事在 rnx-ui/Overlay 组件的使用过程中发现的(已在 [email protected]
版本中修复)。下面就结合 Overlay
组件介绍下该问题的3个解法。
最初 Overlay
组件结构如下:
<TouchableWithoutFeedback>
<View>
{ this.props.children }
</View>
</TouchableWithoutFeedback>
实际使用产生结构如下:
<TouchableWithoutFeedback>
<View>
<ScrollView>
{ list }
</ScrollView>
</View>
</TouchableWithoutFeedback>
只要 Overlay
不捕获自组件的触摸事件就好了。View
组件有个属性叫做 pointerEvents
,用来控制 View
是否可以作为触控事件的目标。(具体参考:https://facebook.github.io/react-native/docs/view.html#pointerevents)
可以通过如下写法让 Touchable*
组件内部元素的触摸事件无法被外层捕获:
<TouchableWithoutFeedback>
<View pointerEvents="box-none">
<ScrollView>
{ list }
</ScrollView>
</View>
</TouchableWithoutFeedback>
设置 pointerEvents
的值为 box-none
,让 View
无法接受触摸事件,但是它的子元素可以。这样就避免了 ScrollView
内部触摸事件被外层捕获导致卡顿。
作为 Overlay
组件的话,就无法实现“点击遮罩消失”这类功能了。
阻止 ScrollView
组件的事件冒泡到外层也可以解决问题。ScrollView
内部用 Touchable*
组件包裹即可:
<TouchableWithoutFeedback>
<View>
<ScrollView>
<TouchableWithoutFeedback>
{ list }
</TouchableWithoutFeedback>
</ScrollView>
</View>
</TouchableWithoutFeedback>
需要业务特别处理
从根本解决问题,将触摸事件处理层(遮罩层)和子组件层的层级关系由父子关系改为兄弟关系,而视觉上遮罩层在子组件层后面的效果则由样式来实现:
<View>
<TouchableWithoutFeedback>
<View />
</TouchableWithoutFeedback>
{ this.props.children }
</View>
无。本该如此。
归根结底,还是一个设计问题。