Skip to content

Commit

Permalink
feat(hippy-react): add system event instance
Browse files Browse the repository at this point in the history
  • Loading branch information
zoomchan-cxj committed Dec 6, 2021
1 parent a2089e4 commit bc0e6ac
Show file tree
Hide file tree
Showing 12 changed files with 265 additions and 131 deletions.
226 changes: 130 additions & 96 deletions docs/hippy-react/gesture.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,20 +16,25 @@ Hippy 的手势系统使用起来相对更加便捷,主要区别就在不需
通过配合使用 onPressIn 和 onPressOut 可以实现点击态的效果,例如下面的示例代码,实现了点击时背景变色的功能:

```jsx
render() {
let bgColor = "#FFFFFF"; //非点击状态下背景为白色
if (this.state.pressedIn) {
bgColor = "#000000"; //点击状态下背景为黑色
}

return (
<View style={{backgroundColor: bgColor}}
onPressIn={() => { this.setState({pressedIn: true}) }}
onPressOut={() => { this.setState({pressedIn: false}) }}
>
点击按钮
</View>
);
render()
{
let bgColor = "#FFFFFF"; //非点击状态下背景为白色
if (this.state.pressedIn) {
bgColor = "#000000"; //点击状态下背景为黑色
}

return (
<View style={{backgroundColor: bgColor}}
onPressIn={() => {
this.setState({pressedIn: true})
}}
onPressOut={() => {
this.setState({pressedIn: false})
}}
>
点击按钮
</View>
);
}
```

Expand Down Expand Up @@ -73,38 +78,54 @@ render() {
1. 返回 `true``没有返回值`:控件处理完事件后,将不再继续冒泡,整个手势事件处理结束;
2. 返回 `false`:控件处理完事件后,事件将继续往上一层冒泡,如果找到某个父控件也设置了对应事件处理函数,则会调用改该回调函数,并再次根据其返回值决定是否继续冒泡。如果再向上冒泡的过程中达到了根节点,则事件冒泡结束;

`2.11.2 版本` 开始,系统 `onClick``onTouchEvent` 事件回调函数添加了 `Event` 实例参数,包含了 `target` 属性(事件的真正发出节点)、`currentTarget`
属性(监听事件的节点)、`stopPropagation` 方法。`stopPropagation` 在开启全局冒泡后能阻止冒泡,优先级高于回调函数 `return 返回值``return 返回值` 后面逐渐废弃。

我们通过以下示例进一步说明事件冒泡的机制:

```js
render() {
return (
<View style={{ width: 300, height: 200, backgroundColor: "#FFFFFF" }}
onClick={() => { console.log("根节点 点击"); }}
>
<Text style={{ width: 150, height: 100, backgroundColor: "#FF0000" }}
onClick={() => console.log("按钮1 点击")}
>
点击按钮1
</Text>
<View style={{ width: 150, height: 100, backgroundColor: "#00FF00" }}
onClick={() => {
console.log("父控件 点击");
// 不再向上冒泡到跟节点
return true;
}}
>
<Text style={{ width: 80, height: 50, backgroundColor: "#0000FF" }}
onClick={() => {
console.log("按钮2 点击");
// 向上冒泡到父控件
return false;
}}
render()
{
return (
<View style={{width: 300, height: 200, backgroundColor: "#FFFFFF"}}
onClick={() => {
console.log("根节点 点击");
}}
>
点击按钮2
</Text>
</View>
</View>
);
<Text style={{width: 150, height: 100, backgroundColor: "#FF0000"}}
onClick={() => console.log("按钮1 点击")}
>
点击按钮1
</Text>
<View style={{width: 150, height: 100, backgroundColor: "#00FF00"}}
onClick={() => {
console.log("父控件 点击");
// 不再向上冒泡到跟节点
return true;
}}
>
<Text style={{width: 80, height: 50, backgroundColor: "#0000FF"}}
onClick={() => {
console.log("按钮2 点击");
// 向上冒泡到父控件
return false;
}}
>
点击按钮2
</Text>
<Text style={{width: 80, height: 50, backgroundColor: "#0000FF"}}
onClick={(event) => {
console.log("按钮2 点击", event.target.nodeId, event.currentTarget.nodeId);
event.stopPropagation();
// 调用了 stopPropagation 后,即使 return false,按钮2点击事件也不会向上冒泡到父节点
return false;
}}
>
点击按钮3
</Text>
</View>
</View>
);
}
```

Expand All @@ -125,76 +146,89 @@ new Hippy({

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

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

例子如下:

```js
render() {
return (
<View style={{ width: 300, height: 200, backgroundColor: "#FFFFFF" }}
onClick={() => { console.log("根节点 点击"); }}
onClickCapture={() => console.log("根节点 捕获点击")}
>
<Text style={{ width: 150, height: 100, backgroundColor: "#FF0000" }}
onClick={() => {
// 点击按钮1不会触发根节点捕获点击
console.log("按钮1 点击")
}}
>
点击按钮1
</Text>
<View style={{ width: 150, height: 100, backgroundColor: "#00FF00" }}>
<Text style={{ width: 80, height: 50, backgroundColor: "#0000FF" }}
onClickCapture={() => {
// 点击按钮2会触发根节点捕获点击
console.log("按钮2 点击");
}}
render()
{
return (
<View style={{width: 300, height: 200, backgroundColor: "#FFFFFF"}}
onClick={() => {
console.log("根节点 点击");
}}
onClickCapture={() => console.log("根节点 捕获点击")}
>
点击按钮2
</Text>
</View>
</View>
);
<Text style={{width: 150, height: 100, backgroundColor: "#FF0000"}}
onClick={() => {
// 点击按钮1不会触发根节点捕获点击
console.log("按钮1 点击")
}}
>
点击按钮1
</Text>
<View style={{width: 150, height: 100, backgroundColor: "#00FF00"}}>
<Text style={{width: 80, height: 50, backgroundColor: "#0000FF"}}
onClickCapture={() => {
// 点击按钮2会触发根节点捕获点击
console.log("按钮2 点击");
}}
>
点击按钮2
</Text>
</View>
</View>
);
}
```

## 事件的拦截

某些场景下,父控件又需要优先拦截到子控件的手势事件,因此 Hippy 也提供了手势事件拦截机制,手势拦截由父控件的两个属性控制 `onInterceptTouchEvent``onInterceptPullUpEvent`,这两个属性仅对能容纳子控件的组件生效,如 `<Image/>` 这种控件就不支持这两个属性:
某些场景下,父控件又需要优先拦截到子控件的手势事件,因此 Hippy 也提供了手势事件拦截机制,手势拦截由父控件的两个属性控制 `onInterceptTouchEvent``onInterceptPullUpEvent`
,这两个属性仅对能容纳子控件的组件生效,如 `<Image/>` 这种控件就不支持这两个属性:

- onInterceptTouchEvent:父控件是否拦截所有子控件的手势事件,true 为拦截,false 为不拦截(默认为 false)。当父控件设置该属性为 true 时,所有其子控件将无法收到任何 touch 事件和点击事件的回调,不管是否有设置事件处理函数,在该父控件区域内按下、移动、抬起手指以及点击和长按发生时,终端将默认把事件发送给该父控件进行处理。如果父控件在设置 onInterceptTouchEvent 为 true 之前,子控件已经在处理 touch 事件,那么子控件将收到一次 onTouchCancel 回调(如果子控件有注册该函数);
- onInterceptPullUpEvent:该属性的作用与 onInterceptTouchEvent 类似,只是决定父控件是否拦截的条件稍有不同。为 true 时,如果用户在当前父控件区域内发生了手指上滑的动作,后续所有的触屏事件将被该父控件拦截处理,所有其子控件将无法收到任何 touch 事件回调,不管是否有设置 touch 事件处理函数;如果拦截生效之前子控件已经在处理 touch 事件,子控件将收到一次 onTouchCancel 回调。为 false 时,父控件将不会拦截事件,默认为 false
- onInterceptTouchEvent:父控件是否拦截所有子控件的手势事件,true 为拦截,false 为不拦截(默认为 false)。当父控件设置该属性为 true 时,所有其子控件将无法收到任何 touch
事件和点击事件的回调,不管是否有设置事件处理函数,在该父控件区域内按下、移动、抬起手指以及点击和长按发生时,终端将默认把事件发送给该父控件进行处理。如果父控件在设置 onInterceptTouchEvent 为 true
之前,子控件已经在处理 touch 事件,那么子控件将收到一次 onTouchCancel 回调(如果子控件有注册该函数);
- onInterceptPullUpEvent:该属性的作用与 onInterceptTouchEvent 类似,只是决定父控件是否拦截的条件稍有不同。为 true
时,如果用户在当前父控件区域内发生了手指上滑的动作,后续所有的触屏事件将被该父控件拦截处理,所有其子控件将无法收到任何 touch 事件回调,不管是否有设置 touch 事件处理函数;如果拦截生效之前子控件已经在处理 touch
事件,子控件将收到一次 onTouchCancel 回调。为 false 时,父控件将不会拦截事件,默认为 false

注意,由于这两种标记拦截条件不同,onInterceptTouchEvent 标记设置为 true 之后,子控件的所有触屏事件都将失效,而 onInterceptPullUpEvent 则不会影响子控件的点击事件。

还是以代码为例:

```js
render() {
return (
<View style={{ width: 300, height: 200, backgroundColor: "#FFFFFF" }}
onTouchMove={(event) => { console.log("根节点 TouchMove:" + JSON.stringify(event)); }}
>
<View style={{ width: 150, height: 100, backgroundColor: "#FF0000" }}
onTouchMove={evt => console.log("红色区域 TouchMove:" + JSON.stringify(event)) }
onTouchDown={(event) => {
console.log("红色区域 onTouchDown:" + JSON.stringify(event));
}}/>
<View style={{ width: 150, height: 100, backgroundColor: "#00FF00" }}
onTouchMove={(event) => {
console.log("绿色区域 TouchMove:" + JSON.stringify(event));
return false;
}}
onInterceptTouchEvent={true}
>
<View style={{ width: 80, height: 50, backgroundColor: "#0000FF" }}
onTouchMove={(event) => {
console.log("蓝色区域 TouchMove:" + JSON.stringify(event));
return false;
}}/>
</View>
</View>
);
render()
{
return (
<View style={{width: 300, height: 200, backgroundColor: "#FFFFFF"}}
onTouchMove={(event) => {
console.log("根节点 TouchMove:" + JSON.stringify(event));
}}
>
<View style={{width: 150, height: 100, backgroundColor: "#FF0000"}}
onTouchMove={evt => console.log("红色区域 TouchMove:" + JSON.stringify(event))}
onTouchDown={(event) => {
console.log("红色区域 onTouchDown:" + JSON.stringify(event));
}}/>
<View style={{width: 150, height: 100, backgroundColor: "#00FF00"}}
onTouchMove={(event) => {
console.log("绿色区域 TouchMove:" + JSON.stringify(event));
return false;
}}
onInterceptTouchEvent={true}
>
<View style={{width: 80, height: 50, backgroundColor: "#0000FF"}}
onTouchMove={(event) => {
console.log("蓝色区域 TouchMove:" + JSON.stringify(event));
return false;
}}/>
</View>
</View>
);
}
```
2 changes: 1 addition & 1 deletion examples/hippy-react-demo/scripts/hippy-webpack.dev.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ const HippyDynamicImportPlugin = require('@hippy/hippy-dynamic-import-plugin');
const pkg = require('../package.json');
module.exports = {
mode: 'development',
devtool: 'eval-cheap-module-source-map',
devtool: 'eval-source-map',
watch: true,
watchOptions: {
aggregateTimeout: 1500,
Expand Down
29 changes: 19 additions & 10 deletions examples/hippy-react-demo/src/components/ListView/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -66,11 +66,17 @@ const styles = StyleSheet.create({
function Style1({ index }) {
return (
<View style={styles.container}
onClickCapture={() => {
console.log('onClickCapture style1');
onClickCapture={(event) => {
console.log('onClickCapture style1', event.target.nodeId, event.currentTarget.nodeId);
}}
onClick={() => {
console.log('click style1');
onTouchDown={(event) => {
// if stopPropagation && return false called at the same time, stopPropagation has higher priority
event.stopPropagation();
console.log('onTouchDown style1', event.target.nodeId, event.currentTarget.nodeId);
return false;
}}
onClick={(event) => {
console.log('click style1', event.target.nodeId, event.currentTarget.nodeId);
return false;
}}
>
Expand Down Expand Up @@ -207,8 +213,8 @@ export default class ListExample extends React.Component {
}
return (
<View style={styles.container}
onClick={() => {
console.log('click style outer');
onClick={(event) => {
console.log('click style outer', event.target.nodeId, event.currentTarget.nodeId);
// return false means trigger bubble
return false;
}}>
Expand Down Expand Up @@ -239,11 +245,14 @@ export default class ListExample extends React.Component {
const { dataSource } = this.state;
return (
<ListView
onClickCapture={() => {
console.log('onClickCapture listview');
onTouchDown={(event) => {
console.log('onTouchDown ListView', event.target.nodeId, event.currentTarget.nodeId);
}}
onClickCapture={(event) => {
console.log('onClickCapture listview', event.target.nodeId, event.currentTarget.nodeId);
}}
onClick={() => {
console.log('click listview');
onClick={(event) => {
console.log('click listview', event.target.nodeId, event.currentTarget.nodeId);
// return false means trigger bubble
return false;
}}
Expand Down
18 changes: 10 additions & 8 deletions examples/hippy-react-demo/src/components/PullHeader/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -164,9 +164,10 @@ export default class PullHeaderExample extends React.Component {
* @param {number} index - 被点击的索引号
*/
// eslint-disable-next-line class-methods-use-this
onClickItem(index) {
onClickItem(index, event) {
// let target = event.target;
// eslint-disable-next-line no-console
console.log(`item: ${index} is clicked..`);
console.log(`item: ${index} is clicked..`, event.target.nodeId, event.currentTarget.nodeId);
}

/**
Expand Down Expand Up @@ -234,13 +235,13 @@ export default class PullHeaderExample extends React.Component {
const isLastItem = dataSource.length === index + 1;
switch (rowData.style) {
case 1:
styleUI = <Style1 itemBean={rowData.itemBean} onClick={() => this.onClickItem(index)} />;
styleUI = <Style1 itemBean={rowData.itemBean} onClick={event => this.onClickItem(index, event)} />;
break;
case 2:
styleUI = <Style2 itemBean={rowData.itemBean} onClick={() => this.onClickItem(index)} />;
styleUI = <Style2 itemBean={rowData.itemBean} onClick={event => this.onClickItem(index, event)} />;
break;
case 5:
styleUI = <Style5 itemBean={rowData.itemBean} onClick={() => this.onClickItem(index)} />;
styleUI = <Style5 itemBean={rowData.itemBean} onClick={event => this.onClickItem(index, event)} />;
break;
case STYLE_LOADING:
styleUI = <Text style={styles.loading}>{loadingState}</Text>;
Expand Down Expand Up @@ -269,9 +270,10 @@ export default class PullHeaderExample extends React.Component {
const { dataSource } = this.state;
return (
<ListView
ref={(ref) => {
this.listView = ref;
}}
onClick={event => console.log('ListView', event.target.nodeId, event.currentTarget.nodeId)}
ref={(ref) => {
this.listView = ref;
}}
style={{ flex: 1, backgroundColor: '#ffffff' }}
numberOfRows={dataSource.length}
getRowType={this.getRowType}
Expand Down
2 changes: 1 addition & 1 deletion examples/hippy-react-demo/src/shared/UIStyles/Style1.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ export default function Style1(props) {
}

return (
<View {...props}>
<View {...props} style={{ collapsable: false }}>
<Text style={[styles.title]} numberOfLines={2} enableScale>
{title}
</Text>
Expand Down
2 changes: 1 addition & 1 deletion examples/hippy-react-demo/src/shared/UIStyles/Style2.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ export default function Style2(props) {
);
}
return (
<View style={styles.container}>
<View {...props} style={styles.container}>
<View style={styles.leftContainer}>
<Text style={styles.title} numberOfLines={2} enableScale>{title}</Text>
{
Expand Down
2 changes: 1 addition & 1 deletion examples/hippy-react-demo/src/shared/UIStyles/Style5.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ export default function Style5(props) {
);
}
return (
<View>
<View {...props}>
<Text style={styles.text} numberOfLines={2} enableScale>
{title}
</Text>
Expand Down
Loading

0 comments on commit bc0e6ac

Please sign in to comment.