摘要:组件事件响应在构建虚拟的同时,还构建了自己的事件系统且所有事件对象和规范保持一致。的事件系统和浏览器事件系统相比,主要增加了两个特性事件代理和事件自动绑定。
React组件事件响应
React在构建虚拟DOM的同时,还构建了自己的事件系统;且所有事件对象和W3C规范
保持一致。
React的事件系统和浏览器事件系统相比,主要增加了两个特性:事件代理、和事件自动绑定。
1、事件代理区别于浏览器事件处理方式,React并未将事件处理函数与对应的DOM节点直接关联,而是在顶层使用
了一个全局事件监听器监听所有的事件;
React会在内部维护一个映射表记录事件与组件事件处理函数的对应关系;
当某个事件触发时,React根据这个内部映射表将事件分派给指定的事件处理函数;
当映射表中没有事件处理函数时,React不做任何操作;
当一个组件安装或者卸载时,相应的事件处理函数会自动被添加到事件监听器的内部映射表中或从表中删除。
2、事件自动绑定在JavaScript中创建回调函数时,一般要将方法绑定到特定的实例,以保证this的正确性;
2.在React中,每个事件处理回调函数都会自动绑定到组件实例(使用ES6语法创建的例外);
注意:事件的回调函数被绑定在React组件上,而不是原始的元素上,即事件回调函数中的
this所指的是组件实例而不是DOM元素;
了解更多React中的thisReact组件中的this。
3、合成事件与浏览器事件处理稍微有不同的是,React中的事件处理程序所接收的事件参数是被称为“合成事件(SyntheticEvent)”的实例。
合成事件是对浏览器原生事件跨浏览器的封装,并与浏览器原生事件有着同样的接口,如stopPropagation(),preventDefault()等,并且
这些接口是跨浏览器兼容的。
如果需要使用浏览器原生事件,可以通过合成事件的nativeEvent属性获取
React合成事件原理
使用JSX,在React中绑定事件:
React并不是将click事件绑在该div的真实DOM上,而是在document处监听所有支持的事件,当事件发生并冒泡至document处时,React将事件内容封装并交由真正的处理函数运行
每个合成事件有以下通用属性:
- boolean bubbles - boolean cancelable - DOMEventTarget currentTarget - boolean defaultPrevented - number eventPhase - boolean isTrusted - DOMEvent nativeEvent - void preventDefault() - boolean isDefaultPrevented() - void stopPropagation() - boolean isPropagationStopped() - DOMEventTarget target - number timeStamp - string type
注意:现版本React在事件处理程序通过中返回false停止传播,已不可用;
取而代之的是需要手动调用e.stopPropagation()或e.preventDefalult().
onCopy onCut onPaste
2、键盘事件onKeyDown onKeyPress onKeyUp
3、焦点事件onFocus onBlur
这些焦点事件工作在 React DOM 中所有的元素上 ,不仅是表单元素。
4、表单事件onChange onInput onSubmit
onChange事件经过React改良,内容改变时即可实时触发;而原生的需内容改变且失去焦点后触发才触发。
5、鼠标事件onClick onContextMenu onDoubleClick onDrag onDragEnd onDragEnter onDragExit onDragLeave onDragOver onDragStart onDrop onMouseDown onMouseEnter onMouseLeave onMouseMove onMouseOut onMouseOver onMouseUp
onMouseEnter 和 onMouseLeave 事件从离开的元素传播到正在进入的元素,而不是普通的冒泡,并且没有捕获阶段;只有在鼠标指针穿过被选元素时,才会触发。
onMouseOut onMouseOver事件:不论鼠标指针穿过被选元素或其子元素,都会触发。
6、选择事件onSelect
7、触摸事件onTouchCancel onTouchEnd onTouchMove onTouchStart
8、UI事件onScroll
9、滚轮事件onWheel
10、图像事件onLoad onError
11、动画事件onAnimationStart onAnimationEnd onAnimationIteration
12、其他事件onToggle
在React中使用原生事件由于原生事件需要绑定在真实DOM上,所以一般是在 componentDidMount阶段/ref的函数执行阶段进行绑定操作,在componentWillUnmount 阶段进行解绑操作以避免内存泄漏。
import React,{Component} from "react"; import ReactDOM from "react-dom" class ReactEvent extends Component { componentDidMount() { //获取当前真实DOM元素 const thisDOM = ReactDOM.findDOMNode(this); thisDOM.addEventListener("click",this.onDOMClick,false); } componentWillUnmount() { //卸载时解绑事件,防止内存泄漏 const thisDOM = ReactDOM.findDOMNode(this); thisDOM.removeEventListener("click",this.removeDOMClick); } onDOMClick(e){ console.log(e) } render(){ return(合成事件和原生事件混合使用单击原始事件触发) } } export default ReactEvent
响应顺序
import React,{Component} from "react"; import ReactDOM from "react-dom" class ReactEvent extends Component { constructor(props){ super(props) this.state = { value: "" } this.onReactClick = this.onReactClick.bind(this) } componentDidMount() { //获取当前真实DOM元素 const thisDOM = ReactDOM.findDOMNode(this); thisDOM.addEventListener("click",this.onDOMClick,false); } componentWillUnmount() { //卸载时解绑事件,防止内存泄漏 const thisDOM = ReactDOM.findDOMNode(this); thisDOM.removeEventListener("click",this.removeDOMClick); } onDOMClick(e){ console.log("原生事件绑定事件触发") } onReactClick(e){ console.log("React合成事件绑定事件触发") } render(){ return(单击事件触发) } } export default ReactEvent
首先DOM事件监听器被执行,然后事件继续冒泡至document,合成事件监听器再被执行。
即,最终控制台输出为:
原生事件绑定事件触发
合成事件绑定事件触发
阻止冒泡
如果在onDOMClick中调用e.stopPropagtion()
onDOMClick(e){ e.stopPropagation() console.log("原生事件绑定事件触发") }
由于DOM事件被阻止冒泡了,无法到达document,所以合成事件自然不会被触发,控制台输出就变成了:
原生事件绑定事件触发
再测试个复杂的例子
import React,{Component} from "react"; import ReactDOM from "react-dom" class ReactEvent extends Component { constructor(props){ super(props) this.state = { value: "" } this.onReactClick = this.onReactClick.bind(this) this.onReactChildClick = this.onReactChildClick.bind(this) } componentDidMount() { //获取当前真实DOM元素 const thisDOM = ReactDOM.findDOMNode(this); thisDOM.addEventListener("click",this.onDOMClick,false); //获取子元素并绑定事件 const thisDOMChild = thisDOM.querySelector(".child"); thisDOMChild.addEventListener("click",this.onDOMChildClick,false); } onDOMClick(e){ console.log("父组件原生事件绑定事件触发") } onReactClick(e){ console.log("父组件React合成事件绑定事件触发") } onDOMChildClick(e){ e.stopPropagation() console.log("子元素原生事件绑定事件触发") } onReactChildClick(e){ console.log("子元素React合成事件绑定事件触发") } render(){ return(父元素单击事件触发) } } export default ReactEvent
通过设置原生事件绑定为冒泡阶段调用,且每次测试单击子元素按钮:
在子元素原生事件程序中阻止事件传播,则打印出:
子元素原生事件绑定事件触发;
在父元素元素事件程序中阻止事件传播,则打印出:
子元素原生事件绑定事件触发
父组件原生事件绑定事件触发
在子元素React合成事件onClick中阻止事件传播,则打印出:
子元素原生事件绑定事件触发
父组件原生事件绑定事件触发
子元素React合成事件绑定事件触发
在父元素React合成事件onClick中阻止事件传播,则打印出:
子元素原生事件绑定事件触发
父组件原生事件绑定事件触发
子元素React合成事件绑定事件触发
父组件React合成事件绑定事件触发
可以看到若不阻止事件传播每次(单击子元素)事件触发流程是:
Document->子元素(原生事件触发)->父元素(原生事件)->回到Document->React子元素合成事件监听器触发 ->React父元素合成事件监听器触发
其实,React合成事件封装的stopPropagtion函数在调用时给自己加了个isPropagationStopped的标记位来确定后续监听器是否执行。
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/93282.html
摘要:导航组件使用详解注意了,如果有小伙伴们发现运行作者提供的示例项目报如下的错误,可能是大家使用了命令导致的,解决这个错误的办法就是将删除,然后重新使用命令来安装,最后使用来起服务,应该就不报错了。 react-navigation导航组件使用详解 注意了,如果有小伙伴们发现运行作者提供的react-navigation示例项目报如下的错误,可能是大家使用了 yarn install 命...
本文主要讲述ref 的应用仅为父组件调用子组件场景下的应用方式1 Class组件 1. 自定义事件 Parent.js importReact,{Component}from'react'; importChildfrom'./Child'; classParentextendsComponent{ componentDidMount(){ ...
阅读 1580·2021-11-23 09:51
阅读 1164·2019-08-30 13:57
阅读 2223·2019-08-29 13:12
阅读 1990·2019-08-26 13:57
阅读 1155·2019-08-26 11:32
阅读 915·2019-08-23 15:08
阅读 670·2019-08-23 14:42
阅读 3056·2019-08-23 11:41