Skip to content

Commit

Permalink
feat(hippy-react): change event capture handle
Browse files Browse the repository at this point in the history
  • Loading branch information
zoomchan-cxj committed Dec 15, 2021
1 parent 1b300ea commit fb73c63
Show file tree
Hide file tree
Showing 3 changed files with 35 additions and 9 deletions.
16 changes: 11 additions & 5 deletions docs/hippy-react/gesture.md
Expand Up @@ -142,12 +142,15 @@ new Hippy({

## 事件捕获

> 最低支持版本 2.11.2
> 最低支持版本 2.11.5

[[事件捕获范例]](//github.com/Tencent/Hippy/tree/master/examples/hippy-react-demo/src/components/ListView)

点击事件和触屏事件支持事件捕获,如需注册捕获阶段的事件处理函数,则应在目标元素事件名添加 `Capture` 后缀,如 `onClickCapture``onTouchDownCapture`。如果目标元素没有`Capture`
事件处理函数,默认不开启捕获。事件捕获会有一定性能损耗,如非必要尽量不开启。
点击事件和触屏事件支持事件捕获,如需注册捕获阶段的事件处理函数,则应在目标元素事件名添加 `Capture` 后缀,如 `onClickCapture``onTouchDownCapture`

Hippy为了做更好的性能优化,如果目标元素没有 `Capture` 事件处理函数,默认不开启捕获,全局冒泡配置 `bubbles: false` 不会影响捕获开启。事件捕获设计与 Web 标准一致,当在任意一个捕获函数内调用 `stopPropagation` 时,会同时阻止剩余的捕获阶段、目标节点阶段和冒泡阶段执行。

!> 事件捕获会有一定性能损耗,如非必要尽量不开启。

例子如下:

Expand All @@ -159,14 +162,17 @@ render()
onClick={() => {
console.log("根节点 点击");
}}
onClickCapture={() => console.log("根节点 捕获点击")}
onClickCapture={(event) => {
// 如果根节点调用 stopPropagation,则按钮2的 onClickCapture 和按钮1的 onClick 都不会触发
// event.stopPropagation();
console.log("根节点 捕获点击")
}}
>
<Text style={{width: 150, height: 100, backgroundColor: "#FF0000"}}
onClick={() => {
// 点击按钮1不会触发根节点捕获点击
console.log("按钮1 点击")
}}
>
点击按钮1
</Text>
Expand Down
13 changes: 12 additions & 1 deletion examples/hippy-react-demo/src/components/ListView/index.jsx
Expand Up @@ -216,6 +216,14 @@ export default class ListExample extends React.Component {
}
return (
<View style={styles.container}
onClickCapture={(event) => {
console.log('onClickCapture style outer', event.target.nodeId, event.currentTarget.nodeId);
}}
onTouchDown={(event) => {
// outer onTouchDown would not be called, because style1 invoked event.stopPropagation();
console.log('onTouchDown style outer', event.target.nodeId, event.currentTarget.nodeId);
return false;
}}
onClick={(event) => {
console.log('click style outer', event.target.nodeId, event.currentTarget.nodeId);
// return false means trigger bubble
Expand Down Expand Up @@ -252,12 +260,15 @@ export default class ListExample extends React.Component {
console.log('onTouchDown ListView', event.target.nodeId, event.currentTarget.nodeId);
}}
onClickCapture={(event) => {
// if calling capture event stopPropagation in one of node,
// all capture phase left, target phase and bubbling phase would stop.
// event.stopPropagation();
console.log('onClickCapture listview', event.target.nodeId, event.currentTarget.nodeId);
}}
onClick={(event) => {
console.log('click listview', event.target.nodeId, event.currentTarget.nodeId);
// return false means trigger bubble
return false;
return true;
}}
bounces={true}
overScrollEnabled={true}
Expand Down
15 changes: 12 additions & 3 deletions packages/hippy-react/src/events/dispatcher.ts
Expand Up @@ -141,10 +141,14 @@ function doCaptureAndBubbleLoop(originalEventName: string, nativeEvent: NativeEv
currentTarget: getElementFromFiber(nextNodeItem),
});
}
nextNodeItem = nextNodeItem.return;
while (nextNodeItem && !isHostComponent(nextNodeItem.tag)) {
// only handle HostComponent
if (eventQueue.length === 0) {
nextNodeItem = null;
} else {
nextNodeItem = nextNodeItem.return;
while (nextNodeItem && !isHostComponent(nextNodeItem.tag)) {
// only handle HostComponent
nextNodeItem = nextNodeItem.return;
}
}
}
if (eventQueue.length > 0) {
Expand All @@ -156,8 +160,13 @@ function doCaptureAndBubbleLoop(originalEventName: string, nativeEvent: NativeEv
const { eventName, currentTarget: currentTargetNode, listener, isCapture } = listenerObj;
const syntheticEvent = new Event(eventName, currentTargetNode, targetNode);
Object.assign(syntheticEvent, nativeEvent);
// whether it is capture or bubbling event, returning false or calling stopPropagation would both stop phase
if (isCapture) {
listener(syntheticEvent);
// event bubbles flag has higher priority
if (!syntheticEvent.bubbles) {
isStopBubble = true;
}
} else {
isStopBubble = listener(syntheticEvent);
// If callback have no return, use global bubble config to set isStopBubble.
Expand Down

0 comments on commit fb73c63

Please sign in to comment.