15、React系列之 React 事件系统

编程入门 行业动态 更新时间:2024-10-25 20:18:52

15、React系列之  React <a href=https://www.elefans.com/category/jswz/34/1770959.html style=事件系统"/>

15、React系列之 React 事件系统

版权声明:本文为博主原创文章,未经博主允许不得转载。

PS:转载请注明出处 作者:TigerChain 地址: 本文出自TigerChain简书

React 教程系列

教程简介

  • 1、阅读对象

本篇教程适合初学者,老鸟直接略过,如果有误,欢迎指出,谢谢。

  • 2、教程难度

    初级

  • 3、Demo 地址:github/githubchen0…

  • 4、本节 demo 效果图如下:

一、事件和事件系统?

1、什么事件?

事件是一个宏观的概念,在各个领域中含义也不太一样。一般来说 事件就是:比较重大,对一定的人群会产生一定影响的事情。

但是在编程中的事件,是一个抽像的概念,可以理解就是干什么(动作),比如:点击一个按钮是一个事件,刷新网页是一个事件,拖拽,移动等等都是是事件。

事件不能单独工作,事件和事件源,监听器三者联合起来才可以工作,所以我们也可以说,事件的三剑客就是,事件、事件源和监听器。

举个栗子!!!

比如点击一个按钮显示出一句话:" Hello React " ! ,那么分析一下这一事件的过程。

事件:点击 事件源:按钮(发生事件的对象也叫事件的产生器) 监听器:监听着事件处理结果,一般是一个回调函数。

2、什么是事件系统?

软件开发中的事件系统也就是事件处理系统,它包含事件监听,事件分发,事件处理回调等等一系列过程。(个人理解,如有不同理解可以指出)。每个开发平台有自己不同的事件处理机制。

二、React 事件系统

1、跨浏览器使用

React 标准化了事件对象,和浏览器本地事件是是同一个接口( React 也就是把浏览器的事件包装了一把而已),所以它可以工作在所有的浏览器中,可以直接在所有的浏览器使用 React 的事件。

2、React 的事件分类

1、合成事件

一、React 事件和 HTML 事件

在 React 中绑定事件和 HTML 中绑定事件类似,但是还是有以下不同。

  • 1、React 事件的命名是驼峰标志,比如: onClick 而不能是 onclick。
  • 2、在 JSX 中你可以传一个方法去处理函数,而不是一个字符串。
  • 3、React事件并没有原生的绑定在真实的DOM上,而是使用了 行为委托 方式实现事件机制。

举个例子

在 HTML 中一个按钮的点击事件

<button onclick="showImg()">显示图片</button>
复制代码

在 React 中一个按钮的点击事件

<button onClick={showImg}>显示图片</button>
复制代码

PS: 关于 HTML 事件可以看这里:www.runoob/jsref/dom-o…

二、合成事件

用官网的话说:React 实现了一个“合成事件”层(synthetic event system),这个事件模型保证了和 W3C 标准保持一致,所以不用担心有什么诡异的用法,并且这个事件层消除了 IE 与 W3C 标准实现之间的兼容问题。

绑定事件,在 React 合成事件中有三种绑定事件的方式:

  • 1、组件上绑定。

格式:

<Component 事件={this.方法.bind(this)}></Component>
复制代码

实例

import React ,{Component} from 'react';class EventApp extends Component {render(){return(<div><button onClick={this._clickMe.bind(this)}>点击我</button></div>) ; }_clickMe(){alert("组件绑定事件实现方法") ;}}
复制代码

PS:每次点击的时候都要重新绑定一个函数,我们知道函数的创建和销毁是需要开销的,所以这种方式对性能有影响。

  • 2、构造方法中绑定。

格式:

constructor(props){super(props) ;this.方法 = this.方法.bind(this,'event','args') ;// event(事件名) 和 args(参数) 不是必须的。
}
<Component 事件={this.方法}></Component>
复制代码

实例

import React ,{Component} from 'react';class EventApp extends Component {constructor(props){super(props) ;this._clickMe = this._clickMe.bind(this) ;}render(){return(<div><button onClick={this._clickMe}>点击我</button></div>) ; }_clickMe(){alert("构造方法绑定事件实现方法") ;}}
复制代码

使用构造方法绑定事件,只需要绑定一次。而不用每次使用的时候都去绑定。

  • 3、使用箭头函数。

格式:

  <Component 事件={(e) => this.方法(e,args)}</Component> //其中 args (参数)不是必须的。
复制代码

实例

import React ,{Component} from 'react';class EventApp extends Component {constructor(props){super(props) ;}render(){return(<div><button onClick={(e) => this._clickMe(e,"使用箭头函数绑定")}>使用箭头函数绑定事件</button> <p/></div>) ; }_clickMe(e,args){alert("箭头函数绑定事件实现方法") ;alert(args);alert(e);}}
复制代码

PS:使用箭头函数系统就默认把 this 绑定到了 _clickMe 方法中,但是需要注意一点,由于箭头函数绑定是定义在 redner 方法中的,组件的每一次渲染都会创建一个新的箭头函数 [ React 中渲染是经常会发生的]。这种方式和组件上绑定是一个道理,对性能有影响。

总结: 综上所述,我个人建议使用在构造方法中绑定事件的方法这种方式。

三、合成事件绑定事件的处理函数

React 合成事件绑定事件处理的函数涉及到鼠标类,触摸类,键盘类,表单和焦点等。

具体可以看官方 Supported Events 这一小节: facebook.github.io/react/docs/…,这没有什么好说的。

注意:经过上面的分析,我们知道 React 的事件绑定有三种方式,但是我们要注意一点,我们不能直接在组件中监听事件。因为组件是 DOM 元素的包装器,如果在组件中直接监听事件,那么到底事件应该是对应那个 DOM 元素的,是一个 button 的还是一张图片的,你就分不清楚了。这样你也分不清楚它和 props 有啥区别。

比如:定义一个含有按钮的子组件 ShowPlus.js 。然后在父组件中监听事件。

1、错误做法

# ShowPlus.jsimport React, { Component, PropTypes } from 'react';export default class ShowPlus extends Component {constructor(props) {super(props);}render() {return (<div><button> 点我 </button></div>);}
}复制代码

父组件,姑且叫 FatherCom.js

# FatherCom.jsimport React, { Component, PropTypes } from 'react';import ShowPlus from './ShowPlus.js' ;export default class FatherCom extends Component {constructor(props) {super(props);}render() {return (<div><ShowPlus onClick={this._addPlus}/></div>);}_addPlus(){alert("this is a plus") ;}
}复制代码

以上方式是错误的,你把按钮点死它也不会调用的,所以我们不要直接在一个自定义组件上添加监听器。

那么我们如何处理这种情况呢,看过 props 这一节的朋友很快就会有答案的,我们可以把事件处理器当作 props 传递到子组件即可。

2、正确的做法

# ShowPlus.jsimport React, { Component, PropTypes } from 'react';export default class ShowPlus extends Component {constructor(props) {super(props);}render() {return (<div><button onClick={this.props.clickHandler}> 点我 </button></div>);}
}复制代码
# FatherCom.jsimport React, { Component, PropTypes } from 'react';import ShowPlus from './ShowPlus.js' ;export default class FatherCom extends Component {constructor(props) {super(props);}render() {return (<div><ShowPlus clickHandler={this._addPlus}/></div>);}_addPlus(){alert("this is a plus") ;}
}
复制代码

这样我们就采用一个变通的方法,把事件处理器当作一个 props 传递给子组件,然后在组件内部,我们把事件监听到一个 DOM 元素上,并将事件处理设置为我们传递过来的 props 就解决了这种问题。

2、原生事件

原生事件就是浏览器所对应的事件,一般情况下,我们使用 React 提供的合成事件就能满足大部分需求,但是有些情况下,我们不得不使用原生事件,所以必要时合成事件和原生事件要搭配着使用。

什么是原生事件?

比如,你在 componentDidMount 方法中通过 addEventListener 绑定的事件就是原生事件。

由于不是所有的 DOM 都有合成事件的对应物。我们不妨试一下"自定义"一个事件。

1、自定义事件

错误的例子:

import React, { Component, PropTypes } from 'react';/*** 自定义事件*/
export default class CustomEvent extends Component {constructor(props) {super(props);}render() {return (<div><button onCusTomAlert={this._customAlert.bind(this)}>自定义事件</button></div>);}_customAlert(e){alert("custom event") ;}
}复制代码

在上面我们自定义了一个 onCusTomAlert 事件,这是 React 中是行不通的,对于 React 不能识别的事件,我们就要使用原生传统的事件方式 addEventListener 处理。修改上面的代码。

正确的例子:

import React, { Component, PropTypes } from 'react';/*** 自定义事件*/
export default class CustomEvent extends Component {constructor(props) {super(props);}// 组件挂载之后注册监听器componentDidMount(){window.addEventListener("click", this._customAlert);}//组件卸载之后移除监听器componentWillUnmount(){window.removeEventListener("click",this._customAlert) ;}render() {return (<div><button>自定义事件</button></div>);}_customAlert(e){alert("custom event") ;}
}复制代码

以上只是一个例子而已,当然对于按钮来说是有 onClick 事件的。

2、原生事件一定要手动移除

对于原生事件,我们一定要手动移除,否则很可能出现内存泄露的问题,一般情况下,我们在 componentDidMount() 方法中注册原生事件,在 componentWillUnmount() 方法中移除事件。而使用合成事件,则不需要,因为 React 内部已经帮我们处理好了。

3、合成事件和原生事件

对合成事件和原生事件,我们尽量不要合成事件和原生事件混用,只是对于无法使用 React 合成事件解决问题的这一场景,我们才需要去使用原生事件。

1、原生事件的事件冒泡和事件捕获

先来一张图来看看 js 冒泡事件和捕获原型

  • 事件捕获

事件捕获就相当于拿个鱼叉捕鱼一样,从水面上面举起叉子插入到水面水鱼所在的位置,在原生 JS 中,就是从 html 所外层的元素向内层元素触发。

  • 事件冒泡:

事件冒泡和事件捕获刚好相反,就想当鱼从水泡吹出一个泡泡到水面上,是从 html 内层元素到外层元素触发的。

  • 举个栗子!

有一个 div 里面有个 button

<div><button>点我</button>
</div>
复制代码

假设这两个元素都绑定了 onclick 事件,如果用户点击了 button ,它在 div 和 p 上都触发了 click 事件,那么执行事件的顺序是如何呢?

事件冒泡:button [子元素先触发] 先触发事件,再到 div

事件捕获:div 先触发事件,再到 button

但是在不同的浏览器中处理是不同的,IE 浏览器仅支持事件冒泡,Netscape 支持事件冒泡。

开发人员可以自己选择绑定事件采用冒泡还是捕获,可以通过方法 addEventListener 的第三个参数来指定。

el.addEventListener('someEvent',doSomething,true)
复制代码

第三个参数如果为 true 就是事件捕获,如果是 false 就是事件冒泡。

但是 IE 浏览器除外( IE 只支持事件冒泡),也不支持 addEventListener 函数,他有一个自己的函数叫 el.attachEvent("onclick", doSomething);

2、事件传播是可以阻止的(原生事件)

(1)、禁止事件冒泡

  • 1、在 W3C 中,使用 stopPropagation() 方法。
  • 2、在 IE 下,设置 window.event.cancelBubble = true。

(2)、禁止默认事件

  • 1、阻止默认浏览器动作(W3C)使用, e.preventDefault()。

  • 2、IE中阻止函数器默认动作的方式 , window.event.returnValue = false。

具体可以看这篇文章

3、注意点

  • 1、阻止 React 合成事件冒泡,并不能阻止原生事件的冒泡,就算使用 stopPropagation 也无法阻止原生事件的冒泡。
  • 2、取消原生事件的冒泡也会同时取消 React 事件,并且原生事件的冒泡在 React 事件的触发和冒泡之前。

以上就是 React 的事件系统,信息量还是比较大的,希望大家多多实践。

Demo 地址: github/githubchen0…

据说点喜欢的人都能成为大神。

更多推荐

15、React系列之 React 事件系统

本文发布于:2024-02-08 21:38:41,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1675337.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:事件   系统   系列之   React

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!