之前写在react上写dom事件大部分都是PC端,基本是click事件,没遇到过什么问题。这次要写一个移动端的项目,需要用到touch事件,对这块不熟悉,趁机学习一边react官网的事件相关的内容。特此记录
react提供了一个合成的事件对象SyntheticEvent,他保证了在不同浏览器下事件对象的统一。下面是官方提供的合成事件对象所具有的的属性:
里边的nativeEvent是浏览器自身提供的事件对象,我使用touch事件想要获取到接触点的相关信息就从这里边取得。
因为react事件的名称与原生不太相同,用时可以在文档查找。
第一种方式:在事件上使用bind(this)
第二种方式:在构造函数中改变this指向
第三种方式:使用=()=>
JavaScript函数中的this不是在函数声明的时候定义的,而是在函数调用(即运行)的时候定义的。在react中也遵循这个原则,this指向该function的调用方,所以“调用者”不同会导致this的不同,这里的“调用者”指的是函数执行时的当前对象。
箭头函数或是bind会改变this的指向。上面的thisstate,之所以能够访问到state就是改变了this的指向,不然getData里的this就是指向这个function,这是的this是undefined。
一般来说:
1、谁调用的this就指向谁。
2、箭头函数,bind改变后的指向父层。
在react中我们使用setState来更新数据:
但是console打印出来的值是:原数据。
这里就要提到react里setState的异步了,在react里setState这个方法是异步的,不会按顺序执行,它可能会等待一组state一起进行更新,来提高性能。下面提供一个解决办法,setState的回调setState(updater[, callback]),相当于componentDidUpdate函数:
因为在事件中使用onClick={thissetData()}时方法直接执行,直接写成thissetData(data)这样会报错,所以需要使用bind():
下面看如何传递:
事件对象:在出发DOM上的某个事件时,会产生一个事件对象event,这个对象中包含着所有与事件有关的信息。
给标签添加ref属性,在事件里通过thisrefs[属性]value来获取值
双向数据绑定在vue中有,在react中是没有的,双向数据绑定就是双方的数据改变相互影响,下面只是模拟双向数据绑定:
上面的的value需要事件监听,这里面有一个react的知识点: 约束性组件和非约束性组件 。
约束性组件,简单说就是react管理了它的value,而非约束性组件的value是由原生DOM管理的。
约束性组件是这样写的:
这里的value属性不再是一个写死的值,它是thisstatedata,而thisstatedata是由thisinputDataChange这个监听事件负责管理的。
这个时候实际上 input 的 value 根本不是用户输入的内容。而是onChange 事件触发之后,由 thissetState 导致了一次重新渲染。不过React会优化这个渲染过程,实际它依然是通过设置input的value来实现的。
非约束性组件是这样写的:
这个defaultValue就是原生DOM中的value属性,其value值就是用户输入的内容,react不管理输入的过程。
对比约束性组件和非约束性组件的输入流程:
约束性组件: 用户输入A -> 触发onChange事件 -> inputDataChange 中设置 statename = “A” -> 渲染input使他的value变成A
非约束性组件: 用户输入A -> input 中显示A
这里介绍form表单里的几种常用的子标签:
一般表单都是需要用form标签包起来:
1、react的组件从概念上看就是一个函数,可以接受一个参数最为输入值,这个参数就是props,可以把props理解为从外部传入组件内部的数据。
2、props经常被用作渲染组件和初始化状态,当一个组件被实例化之后,它的props是只读的,不可改变的。如果props在渲染过程中可以被改变,会导致这个组件显示的形态变得不可预测。只有通过父组件重新渲染的方式才可以把新的props传入组件中。
3、在组件中,我们最好为props中的参数设置一个defaultProps,并且制定它的类型。
一个组件的显示形态可以由数据状态和外部参数所决定,外部参数也就是props,而数据状态就是state
state的主要作用是用于组件保存、控制以及修改自己的状态,它只能在constructor中初始化,它算是组件的私有属性,不可通过外部访问和修改,只能通过组件内部的thissetState来修改,修改state属性会导致组件的重新渲染。
写在最后:
DOM事件发生之后,React通过事件委托减大部分事件代理至Document层
1 ReactEventListener:负责给元素绑定事件
2 ReactEventEmitter:暴露接口给React组件层用于添加事件订阅
3 EventPluginHub负责管理和注册各种插件
4 事件分发的时候React事件系统使用了插件机制来管理不同的事件
1 可以进行浏览器原生事件的封装,对浏览器兼容性进行处理
2 React通过syntheticEvent实现跨平台的事件机制
3 原生事件的升级和改造
1 负责事件类型blur,focus,click,submit,touchMove,mouseMove,scroll,drag,load
2 事件模型符合标准的捕获执行,冒泡流程,可以比较简单的绑定在document上面,和原生DOM事件式一一对应的关系,比较好处理
1 负责事件类型
mouseEnter,mouseLeave,pointerEbnter,pointerLeave
2 负责处理一些不支持冒泡的事件
1 负责事件
onTouchTap
2 为了解决ios移动端300ms点击延迟onTouchTap这个事件会忽略300ms后的onClick事件
1 自定义change事件
1 为表单元素规范化了select事件,用于input,textarea,contentEditable元素
1 befoerInput事件以及composition事件当用户使用拼音输入法输入汉字的时候,这个事件就会被触发
1 form 的submit,reset
2 媒体触发事件,video/audio的相关事件onplaying,onprogress,onratechange事件
1 discreateEvent离散事件
2 UserblockingEvent用户阻塞事件:这些事件会阻塞用户的交互,优先级是1
3 continuousEvent连续事件优先级是2,最高,不会被打断
如上图所示:
在JavaScript中,事件的触发实质上是要经过三个阶段:事件捕获、目标对象本身的事件处理和事件冒泡。
事件委托的实质就是将子元素事件的处理委托给父级元素处理。把事件监听器添加到它们的父元素上。事件监听器会分析从子元素冒泡上来的事件,找到它是哪个子元素的事件。
举个栗子:如果我们有一个列表,列表之中有大量的列表项,我们需要在点击列表项的时候响应一个事件
事件委托优点 :
不适用的情况: 比如 focus、blur 之类的事件本身没有事件冒泡机制,所以无法委托; mousemove、mouseout这样的事件,虽然有事件冒泡,但是只能不断通过位置去计算定位,对性能消耗高,因此也是不适合于事件委托。
在 React事件介绍 中介绍了合成事件对象以及为什么提供合成事件对象,主要原因是因为 React 想实现一个全浏览器的框架, 为了实现这种目标就需要提供全浏览器一致性的事件系统,以此抹平不同浏览器的差异。
合成事件对象很有意思,一开始听名字会觉得很奇怪,看到英文名更奇怪 SyntheticEvent , 实际上合成事件的意思就是使用原生事件合成一个 React 事件, 例如使用原生 click 事件合成了 onClick 事件,使用原生 mouseout 事件合成了 onMouseLeave 事件,原生事件和合成事件类型大部分都是一一对应,只有涉及到兼容性问题时我们才需要使用不对应的事件合成。
合成事件是浏览器的原生事件的跨浏览器包装器。除兼容所有浏览器外,它还拥有和浏览器原生事件相同的接口,包括 stopPropagation() 和 preventDefault() 。
当我们在组件上设置事件处理器时,React并不会在该DOM元素上直接绑定事件处理器 React内部自定义了一套事件系统,在这个系统上统一进行事件订阅和分发。
具体来讲,React利用事件委托机制在Document上统一监听DOM事件,再根据触发的target将事件分发到具体的组件实例。另外上面e是一个合成事件对象(SyntheticEvent), 而不是原始的DOM事件对象。
React事件系统实现可以分为两个阶段:事件注册、事件触发
ReactBrowserEventEmitter作为事件注册入口,担负着事件注册和事件触发。注册事件的回调函数由EventPluginHub来统一管理,根据事件的类型(type)和组件标识(_rootNodeID)为key唯一标识事件并进行存储。
其大致流程如下:
简单点的解释为:
React不会将事件处理函数直接绑定到真实的节点上,而是把所有的事件绑定到结构的最外层,使用一个统一的事件监听器。这个监听器维持了一个映射,保存所有组件内部的事件监听和处理函数。当事件发生时,首先被这个统一的事件监听器处理,然后在映射里找到真正的事件处理函数并调用。
需要注意的是
关于合成事件
合成事件官方文档: >
1 当写在div上的事件被委托给document之后,监听方法发生了怎样的变化
2 以一个click事件为例click事件属于离散事件,优先级较低
3 离散事件的监听并不会立即执行,而是以一定的优先级进行调度
4 Fiber 允许一个任务在页面渲染比较繁忙的时候不执行更新,等待浏览器空闲的时候执行。但是这个延后是有限制的,比如对于同步任务,过期时间就是 -1,表示同步任务需要立即执行。对于优先级是 UserBlockingPriority,过期时间是 250,也就是允许最长延期 250ms 执行。这个优先级还是比较高的
5 事件分为三类:分别是离散事件,用户阻塞事件,连续事件连续事件不会经过调度,而是直接执行
6 离散事件和用户阻塞事件执行调度的优先级相同,不同点在于离散事件执行调度q会把之前未执行的事件以同步的方式执行掉
7 一个nativeEvent在进入调度,也就是开始执行回调的时候,首先会根据nativeEvent获得事件发生时的目标节点,以及对应的fiber对象然后根据这些信息去React的事件插件种获得该原生事件对应的sytheticEvent合成事件一个原生事件可以对应多个合成事件
8 多个合成事件一次执行dispatchlisteners中存储的监听方法,在每个监听事件中判断事件是否停止传播
9 事件执行完毕之后,判断用户是否设置额事件持久化,如果没有,重置事件中的属性,放入事件缓存池保存
1 父组件 -> 前几层子组件: props 2 父组件 -> 非常深入的子组件(比如从最顶层到第5层以后): context 这种情况几乎很少见,除非写框架或者工具,最好是只用props,清晰明了 3 子组件 -> 父组件:callback 4 子组件时间:
以上就是关于React事件系统之touch全部的内容,包括:React事件系统之touch、react表单和绑定事件及state和props-04、React 事件委托等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)