Fork me on GitHub
大洋

专注于前端


  • 首页

  • 分类

  • 归档

  • 标签

react事件研究及阻止冒泡

发表于 2017-08-25 |

React 中的事件处理逻辑

为了解决跨浏览器兼容性问题,React 会将浏览器原生事件(Browser Native Event)封装为合成事件(SyntheticEvent)传入设置的事件处理器中。这里的合成事件提供了与原生事件相同的接口,不过它们屏蔽了底层浏览器的细节差异,保证了行为的一致性。另外有意思的是,React 并没有直接将事件附着到子元素上,而是以单一事件监听器的方式将所有的事件发送到顶层进行处理。这样 React 在更新 DOM 的时候就不需要考虑如何去处理附着在 DOM 上的事件监听器,最终达到优化性能的目的。

合成事件 SyntheticEvent

SyntheticEvent 是浏览器原生事件跨浏览器的封装。SyntheticEvent 和浏览器原生事件一样有 stopPropagation()、preventDefault() 接口,而且这些接口夸浏览器兼容。

如果出于某些原因想使用浏览器原生事件,可以使用 nativeEvent 属性获取。每个和成事件(SyntheticEvent)对象都有以下属性:

1
2
3
4
5
6
7
8
9
10
11
12
boolean bubbles
boolean cancelable
DOMEventTarget currentTarget
boolean defaultPrevented
Number eventPhase
boolean isTrusted
DOMEvent nativeEvent
void preventDefault()
void stopPropagation()
DOMEventTarget target
Date timeStamp
String type

支持的事件

React 将事件统一化,使事件在不同浏览器上有一致的属性。

事件处理程序在事件冒泡阶段被触发。如果要注册事件捕获处理程序,应该使用 Capture 事件,例如使用 onClickCapture 处理点击事件的捕获阶段,而不是 onClick。

阻止冒泡事件分三种情况

A、阻止合成事件间的冒泡,用e.stopPropagation();

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
import React,{ Component } from 'react';
import ReactDOM,{findDOMNode} from 'react-dom';

class Counter extends Component{
constructor(props){
super(props);
this.state = {
count:0,
}
}

handleClick(e){
// 阻止合成事件间的冒泡
e.stopPropagation();
this.setState({count:++this.state.count});
}

testClick(){
console.log('test')
}

render(){
return(
<div ref="test" onClick={()=>this.testClick()}>
<p>{this.state.count}</p>
<a ref="update" onClick={(e)=>this.handleClick(e)}>更新</a>
</div>
)
}
}

var div1 = document.getElementById('content');
ReactDOM.render(<Counter/>,div1,()=>{});

B、阻止合成事件与最外层document上的事件间的冒泡,用e.nativeEvent.stopImmediatePropagation();

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
import React,{ Component } from 'react';
import ReactDOM,{findDOMNode} from 'react-dom';

class Counter extends Component{
constructor(props){
super(props);
this.state = {
count:0,
}
}

handleClick(e){
// 阻止合成事件与最外层document上的事件间的冒泡
e.nativeEvent.stopImmediatePropagation();
this.setState({count:++this.state.count});
}

render(){
return(
<div ref="test">
<p>{this.state.count}</p>
<a ref="update" onClick={(e)=>this.handleClick(e)}>更新</a>
</div>
)
}

componentDidMount() {
document.addEventListener('click', () => {
console.log('document');
});
}
}

var div1 = document.getElementById('content');

ReactDOM.render(<Counter/>,div1,()=>{});

C、阻止合成事件与除最外层document上的原生事件上的冒泡,通过判断e.target来避免

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
import React,{ Component } from 'react';
import ReactDOM,{findDOMNode} from 'react-dom';

class Counter extends Component{
constructor(props){
super(props);

this.state = {
count:0,
}
}

handleClick(e){
this.setState({count:++this.state.count});
}
render(){
return(
<div ref="test">
<p>{this.state.count}</p>
<a ref="update" onClick={(e)=>this.handleClick(e)}>更新</a>
</div>
)
}

componentDidMount() {
document.body.addEventListener('click',e=>{
// 通过e.target判断阻止冒泡
if(e.target&&e.target.matches('a')){
return;
}
console.log('body');
})
}
}

var div1 = document.getElementById('content');

ReactDOM.render(<Counter/>,div1,()=>{});

stackoverflow

https://stackoverflow.com/questions/24415631/reactjs-syntheticevent-stoppropagation-only-works-with-react-events

React uses event delegation with a single event listener on document for events that bubble, like ‘click’ in this example, which means stopping propagation is not possible; the real event has already propagated by the time you interact with it in React. stopPropagation on React’s synthetic event is possible because React handles propagation of synthetic events internally.

Working JSFiddle with the fixes from below: http://jsfiddle.net/7LEDT/6/

React Stop Propagation on jQuery Event

Use Event.stopImmediatePropagation to prevent your other (jQuery in this case) listeners on the root from being called. It is supported in IE9+ and modern browsers.

1
2
3
4
stopPropagation: function(e){
e.stopPropagation();
e.nativeEvent.stopImmediatePropagation();
},

  • Caveat: Listeners are called in the order in which they are bound. React must be initialized before other code (jQuery here) for this to work.

jQuery Stop Propagation on React Event

Your jQuery code uses event delegation as well, which means calling stopPropagation in the handler is not stopping anything; the event has already propagated to document, and React’s listener will be triggered.

1
2
3
4
// Listener bound to `document`, event delegation
$(document).on('click', '.stop-propagation', function(e){
e.stopPropagation();
});

To prevent propagation beyond the element, the listener must be bound to the element itself:

1
2
3
4
// Listener bound to `.stop-propagation`, no delegation
$('.stop-propagation').on('click', function(e){
e.stopPropagation();
});

Clarified that delegation is necessarily only used for events that bubble. For more details on event handling, React’s source has descriptive comments: https://github.com/facebook/react/blob/3b96650e39ddda5ba49245713ef16dbc52d25e9e/src/renderers/dom/client/ReactBrowserEventEmitter.js#L23

JavaScript 中的匿名递归

发表于 2017-08-17 |

代码如果这么写,过一段时间之后自己还能明白?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
(
(
(f) => f(f)
)
(
(f) =>
(l) => {
console.log(l)
if (l.length) f(f)(l.slice(1))
console.log(l)
}
)
)
(
[1, 2, 3]
)

是的,这就是想要分享给大家的一个有趣的示例。这个例子包含以下特性:闭包),自执行函数,箭头函数,函数式编程 和 匿名递归。

你可以复制粘贴上述代码到浏览器控制台,会看到打印结果如下:

1
2
3
4
5
6
7
8
[ 1, 2, 3 ]
[ 2, 3 ]
[ 3 ]
[]
[]
[ 3 ]
[ 2, 3 ]
[ 1, 2, 3 ]

阅读全文 »

八段代码彻底掌握 Promise

发表于 2017-08-01 |

1.Promise的立即执行性

1
2
3
4
5
6
7
8
9
10
var p = new Promise(function(resolve, reject){
console.log("create a promise");
resolve("success");
});

console.log("after new Promise");

p.then(function(value){
console.log(value);
});

控制台输出:

1
2
3
"create a promise"
"after new Promise"
"success"

Promise对象表示未来某个将要发生的事件,但在创建(new)Promise时,作为Promise参数传入的函数是会被立即执行的,只是其中执行的代码可以是异步代码。有些同学会认为,当Promise对象调用then方法时,Promise接收的函数才会执行,这是错误的。因此,代码中”create a promise”先于”after new Promise”输出。

阅读全文 »

webpack的重要功能——Plugins

发表于 2017-06-23 |

webpack中另一个非常重要的功能是Plugins。
插件(Plugins)是用来拓展webpack功能的,它们会在整个构建过程中生效,执行相关的任务。
Loaders和Plugins常常被弄混,但是他们其实是完全不同的东西:Loaders是在打包构建过程中用来处理源文件的(JSX,Scss,Less..),一次处理一个;插件并不直接操作单个文件,它直接对整个构建过程其作用。
webpack有很多内置插件,同时也有很多第三方插件,可以让我们完成更加丰富的功能。

阅读全文 »

webpack最强大的功能———Loaders

发表于 2017-06-23 |

Loaders

Loaders是webpack中最强大的功能之一了。通过使用不同的loader,webpack通过调用外部的脚本或工具可以对各种各样的格式的文件进行处理,如分析JSON文件并把它转换为JavaScript文件;或把下一代的js文件(ES6,ES7)转换为现代浏览器可以识别的JS文件;或对React的开发而言,合适的Loaders可以把react的JSX文件转换为JS文件。

Loaders需要单独安装并且需要在webpack.config.js下的modules关键字下进行配置。安装命令为npm install --save-dev json-loader,Loaders的配置选项包括以下几方面:

  • test 一个匹配loaders所处理的文件的拓展名的正则表达式(必须)
  • loader loader的名称(必须)
  • include/exclude 手动添加必须处理的文件(文件夹)或屏蔽不需要处理的文件(文件夹)(可选)
  • query 为loaders提供额外的设置选项(可选)
    阅读全文 »

浅谈webpack模块引用的五种方法

发表于 2017-06-23 |

commonjs格式的require同步语法

1
2
const home = require('./Home');  
… // 使用

commonjs格式的require.ensure异步语法

1
2
3
4
require.ensure([], require => {  
const home = require('./Home');
… //使用
});
阅读全文 »

webpack入门

发表于 2017-06-22 |

在webpack看来,所有的资源文件都是模块,只是处理的方式不同。
webpack解决的需求点是:如何更好地加载前端模块。

使用webpack

只需要指定一个入口文件,webpack将自动识别项目所依赖的其它文件,不过需要注意的是如果webpack没有进行全局安装,那么在终端中使用此命令时,需要额外指定其在node_modules中的地址。

若webpack全局安装,使用webpack app/main.js public/bundle.js命令即可。
若webpack非全局安装,需使用node_modules.bin\webpack app/main.js public/bundle.js命令。
注意:node_modules.bin\webpack的路径需用右斜杠形式,用左斜杠形式会报错。

阅读全文 »

npmlist

发表于 2017-06-07 |

这里收集了一些目前用到的一些npm库以及相关的功能

node-glob 获取对应规则的文件/路径/所有文件

node的glob模块允许你使用 *等符号, 来写一个glob规则,获取匹配对应规则的文件.
这个glob工具基于javascript.它使用了 minimatch 库来进行匹配
https://github.com/isaacs/node-glob

阅读全文 »

node-glob

发表于 2017-06-02 |

node的glob模块允许你使用 *等符号, 来写一个glob规则,获取匹配对应规则的文件.
这个glob工具基于javascript.它使用了 minimatch 库来进行匹配
https://github.com/isaacs/node-glob

阅读全文 »

inquirer.js-常见的交互式命令行用户接口的集合

发表于 2017-05-31 |

创建交互式命令行用户接口

github地址: https://github.com/SBoudrias/Inquirer.js

阅读全文 »
1…789…12
大洋

大洋

Stay Hungry! Stay Young!

113 日志
57 标签
RSS
GitHub Weibo QQ Mail
友链
  • moxhuis
  • indexof
  • xiaoqiang
© 2016 - 2023 大洋
由 Hexo 强力驱动
主题 - NexT.Muse