feat(hippy-react): change event capture handle

This commit is contained in:
zoomchan-cxj
2021-12-12 06:35:11 -06:00
committed by Zoom Chan
parent 06f4f4e98f
commit 42e16dace5
3 changed files with 35 additions and 9 deletions
+11 -5
View File
@@ -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` 时,会同时阻止剩余的捕获阶段、目标节点阶段和冒泡阶段执行。
!> 事件捕获会有一定性能损耗,如非必要尽量不开启。
例子如下:
@@ -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>
@@ -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
@@ -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}
+12 -3
View File
@@ -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) {
@@ -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.