乐趣区

React-Native-中-Touchable-组件事件捕获问题

RN 中 Touchable* 组件内部元素的触摸事件会被 Touchable* 组件捕获。这个是符合预期的。但是如果 Touchable* 组件内部嵌套一个 ScrollView 组件,会导致 ScrollView 组件滚动异常(卡顿)。

解决

这个问题最初是同事在 rnx-ui/Overlay 组件的使用过程中发现的。下面就结合 Overlay 组件介绍下该问题的 3 个解法。

最初 Overlay 组件结构如下:

<TouchableWithoutFeedback>
  <View>
    {this.props.children}  
  </View>
</TouchableWithoutFeedback>

实际使用产生结构如下:

<TouchableWithoutFeedback>
  <View>
    <ScrollView>
      {list}  
    </ScrollView>
  </View>
</TouchableWithoutFeedback>

解法 1:禁止外层捕获事件

只要 Overlay 不捕获自组件的触摸事件就好了。View 组件有个属性叫做 pointerEvents,用来控制 View 是否可以作为触控事件的目标。(具体参考:https://facebook.github.io/re…)

可以通过如下写法让 Touchable* 组件内部元素的触摸事件无法被外层捕获:

<TouchableWithoutFeedback>
  <View pointerEvents="box-none">
    <ScrollView>
      {list}  
    </ScrollView>
  </View>
</TouchableWithoutFeedback>

设置 pointerEvents 的值为 box-none,让 View 无法接受触摸事件,但是它的子元素可以。这样就避免了 ScrollView 内部触摸事件被外层捕获导致卡顿。

缺点: 作为 Overlay 组件的话,就无法实现“点击遮罩消失”这类功能了。

解法 2:阻止 ScrollView 内部事件冒泡到外层

阻止 ScrollView 组件的事件冒泡到外层也可以解决问题。ScrollView 内部用 Touchable* 组件包裹即可:

<TouchableWithoutFeedback>
  <View>
    <ScrollView>
      <TouchableWithoutFeedback>
      {list}
      </TouchableWithoutFeedback>
    </ScrollView>
  </View>
</TouchableWithoutFeedback>

缺点: 需要业务特别处理

解法 3:改变层级关系

从根本解决问题,将处理触摸事件的层和子组件层的层级关系由父子关系改为兄弟关系:

<View>
  <TouchableWithoutFeedback>
    <View />
  </TouchableWithoutFeedback>
  {this.props.children}
</View>

缺点: 无。本该如此。

总结

归根结底,还是一个设计问题。

退出移动版