在之前的博文中,我们知道怎么给react的class组件的 dom绑定事件了,现在我们在一起实现给react DOM绑定事件
给函数组件绑定事件
function FnEvent(){
function handleClick(e){
console.log(‘this is handle FnEvent‘)
}
return (
<button onClick={handleClick}>FnEvent</button>
)
}
ReactDOM.render(<FnEvent />,document.getElementById(‘function-event‘))
给class组件绑定事件
class ButtonEvent extends React.Component{
constructor(){
super()
this.handleClick = this.handleClick.bind(this)
}
// componentDidMount(){
// console.log(this)
// }
render(){
return (
<button onClick={this.handleClick}>classEvent</button>
)
}
handleClick(){
console.log(this)
}
}
ReactDOM.render(<ButtonEvent />,document.getElementById(‘class-event‘))
通过上面的代码实现,我们可以发现当我们没有给事件函数绑定组件的this
上下文的时候,是访问this
的时候,是
undefined
,因此就有了以下问题
当我们用class创建一个类的时候,实例化对象后调用其静态或者原型方法的时候,如果该对象没有this
值(或this
作为布尔,字符串,数字,未定义或null),那么this
值在被调用的函数内部将为undefined
。
不会发生自动包装。
class Animal{
speak(){
return this
}
static eat(){
return this
}
}
let animal1 = new Animal();
console.log(animal1.speak());//Animal?{}
let speck = animal1.speak
console.log(speck())//undeifined
console.log(Animal.eat());
/*
class Animal{
speak(){
return this
}
static eat(){
return this
}
}
*/
let eat = Animal.eat;
console.log(eat());//undefined
在上述代码中,在类里面声明了一个handleClick函数,然后给按钮绑定事件的时候相当于隐式的将这个函数赋值给
onClick的回调函数callback
,这样的话handClick就失去了上下文,就访问不到this
this.handleClick = this.handleClick.bind(this)
<button onClick={this.handleClick.bind(this)}></button>
<button onClick={(e) => this.handleClick(e)}></button>
class EventPrinciple extends React.Component{
innerClick = e =>{
console.log(‘A: react inner click‘);
};
outerClick = () =>{
console.log("B: react outer click")
};
componentDidMount(){
document.getElementById(‘outer‘).addEventListener(‘click‘,()=>console.log(‘C:native outer click‘));
window.addEventListener(‘click‘,()=>
console.log("D:native window click")
)
}
render(){
return(
<div id=‘outer‘ onClick={this.outerClick}>
<button id=‘inner‘ onClick={this.innerClick}>BUTTON</button>
</div>
)
}
}
ReactDOM.render(<EventPrinciple />,document.getElementById(‘event-principle‘));
上面的代码中,我们在react组件挂载后给‘outer‘绑定了原生事件,同时绑定了react事件,给window绑定了原生事件,给‘inner‘
绑定了react事件,当把react渲染到页面中的时候执行结果如下所示:
由上面的结果,我们可以看出,react事件和原生事件是有区别的
并且我们可以知道React时间和原生事件的执行顺序,由此,我们可以理解:
给innerClick
中的e.stopPropagation()
加上,输出的结果如下
class EventPriciple1 extends React.Component{
constructor(props){
super(props);
this.state = {
editable:false
}
}
handleClick = () => {
console.log(‘edit button click!!!‘);
this.setState({
editable:true
})
};
handleSubmit = e => {
console.log(‘submit event!!‘);
e.preventDefault();//避免页面刷新
};
render(){
return (
<form onSubmit={this.handleSubmit}>
{this.state.editable?(<button type="submit">submit</button>):(
<button type="button" onClick={this.handleClick}>edit</button>
)}
</form>
)
}
}
ReactDOM.render(<EventPriciple1 />,document.getElementById(‘event-principle1‘))
这段代码中,我们给from绑定了一个react事件,在editable为true给按钮(type为button)绑定react事件handleClick
,
点击type为submit的按钮结果如下
edit button click
submit event
点击type为button的按钮结果如下
submit event
从上面两个例子中,我们产生以下两个疑问
DOM事件流
时间流包括三个阶段,简而言之:时间一开始从文档的根节点流向目标对象(捕获阶段),
然后在目标对象上被触发(目标阶段),之后在回溯到文档的根节点(冒泡阶段)。
DOM0级处事件处理程序
<input type="button" value="Click me" id="btn">
<script>
var btn = document.getElementById(‘btn‘);
btn.onclick = function(){
console.log(this.id)
}
</script>
这里是将一个函数赋值给一个事件处理程序的属性,以这种方式添加的时间处理程序会在
时间流的冒泡阶段被处理。要删除事件将btn.onclick = null
即可
DOM2级事件处理程序
DOM2级事件定义了addEventListener()
和removeEventListener()
两个方法,用于处理和删除事件处理程序的操作
所有DOM节点都包含这两个方法,它们接受3个参数:要处理的事件名、作为事件
处理程序的函数和一个布尔值。最后的布尔值参数是true表示在捕获阶段调用事件处理程序,
如果是false(默认)表示在冒泡阶段调用事件处理程序
<input type=‘button‘ value=‘Click me‘ id=‘btn‘ />
<script>
var btn = document.getElementById(‘btn‘);
btn.addEventListener(‘click‘,function(){
console.log(this.id)
},false)
btn.addEventListener(‘click‘,function(){
console.log(‘hello word‘)
},false)
</script>
上面代码两个事件处理程序会按照他们的添加顺序触发,但是如果用的是DOM0
级绑定的事件处理程序,后面的将会覆盖前面的
通过 addEventListener
添加的时间处理程序只能使用removeEventListener
来移除,移除时候传入参数与添加时候的参数相同,即使匿名函数无法被移除
<input type=‘button‘ value=‘Click me‘ id=‘btn‘ />
<scirpt>
var btn = document.getElementById(‘btn‘);
var handler = function(){
console.log(this.id);
}
btn.addEventListener(‘click‘,handler,false);
btn.removeEventListener(‘click‘,handler,false);
</script>
IE事件处理程序
IE通常都是特立独行的,它添加和删除事件处理程序的方法分别是
attachEvent
和detachEvent
同样接受事件处理程序名称与事件处理程序函数两个参数,但跟addEventListener
的区别是:
还有一点需要注意,DOM0和DOM2级的方法,其作用域都是在其所依附的
元素中,attachEvent
则是全局,即如果像之前一样使用this.id
,
访问到的就不是button元素,而是window,就得不到正确的结果
在HTML
中
<button onclick=‘handleClick‘>BUTTON</button>
在React
中
<button onClick={handleClick}>BUTTON</button>
另一个区别是,在React中你不能通过返回false来阻止默认行为。必须明确调用preventDefault
react事件和原生事件可以混用吗?
react事件和原生事件最好不要混用。原生事件中如果执行了stopPropagation方法,
则会导致其他react事件失效。因为所有元素的事件将无法冒泡到document上。由此,react事件都将无法被
注册。
由上面的例子,我们可以看出React自己实现了一套时间机制,自己模拟了时间冒泡和捕获的过程,采用了事件
代理,批量更新的方法,并且抹平了各个浏览器的兼容性的问题。
原文:https://www.cnblogs.com/dehenliu/p/12656001.html