今天给各位分享vue2vue3响应式原理的知识,其中也会对vue的响应原理进行解释,如果能碰巧解决你现在面临的问题,别忘了关注本站,现在开始吧!
本文目录一览:
Vue3.0 响应式原理
Vue3 使用 Proxy 对象重写响应式系统,这个系统主要有以下几个函数来组合完成的:
1、reactive:
接收一个参数,判断这参数是否是对象。不是对象则直接返回这个参数,不做响应式处理
创建拦截器对象 handler, 设置 get/set/deleteProperty
get
收集依赖(track)
返回当前 key 的值。
如果当前 key 的值是对象,则为当前 key 的对象创建拦截器 handler, 设置 get/set/deleteProperty
如果当前的 key 的值不是对象,则返回当前 key 的值
set
设置的新值和老值不相等时,更新为新值,并触发更新(trigger)
deleteProperty
当前对象有这个 key 的时候,删除这个 key 并触发更新(trigger)
返回 Proxy 对象
2、effect: 接收一个函数作为参数。作用是:访问响应式对象属性时去收集依赖
3、track:
接收两个参数:target 和 key
如果没有 activeEffect,则说明没有创建 effect 依赖
如果有 activeEffect,则去判断 WeakMap 集合中是否有 target 属性,
WeakMap 集合中没有 target 属性,则 set(target, (depsMap = new Map()))
WeakMap 集合中有 target 属性,则判断 target 属性的 map 值的 depsMap 中是否有 key 属性
depsMap 中没有 key 属性,则 set(key, (dep = new Set()))
depsMap 中有 key 属性,则添加这个 activeEffect
4、trigger:
判断 WeakMap 中是否有 target 属性
WeakMap 中没有 target 属性,则没有 target 相应的依赖
WeakMap 中有 target 属性,则判断 target 属性的 map 值中是否有 key 属性,有的话循环触发收集的 effect()
聊一聊 Vue3 中响应式原理
Vue.js 3.0 "One Piece" 正式发布已经有一段时间了,真可谓是千呼万唤始出来啊!
相比于 Vue2.x , Vue3.0 在新的版本中提供了更好的性能、更小的捆绑包体积、更好的 TypeScript 集成、用于处理大规模用例的新 API 。
在发布之前,尤大大就已经声明了响应式方面将采用 Proxy 对于之前的 Object.defineProperty 进行改写。其主要目的就是弥补 Object.defineProperty 自身的一些缺陷,例如无法检测到对象属性的新增或者删除,不能监听数组的变化等。
而 Vue3 采用了新的 Proxy 实现数据读取和设置拦截,不仅弥补了之前 Vue2 中 Object.defineProperty 的缺陷,同时也带来了性能上的提升。
今天,我们就来盘一盘它,看看 Vue3 中响应式是如何实现的。
The Proxy object enables you to create a proxy for another object, which can intercept and redefine fundamental operations for that object. MDN
Proxy - 代理,顾名思义,就是在要访问的对象之前增加一个中间层,这样就不直接访问对象,而是通过中间层做一个中转,通过操作代理对象,来实现修改目标对象。
关于 Proxy 的更多的知识,可以参考我之前的一篇文章 —— 初探 Vue3.0 中的一大亮点——Proxy ! ,这里我就不在赘述。
Vue3 中响应式核心方法就是 reactive 和 effect , 其中 reactive 方法是负责将数据变成响应式, effect 方法的作用是根据数据变化去更新视图或调用函数,与 react 中的 useEffect 有点类似~
其大概用法如下:
默认会执行一次,打印 Hello , 之后更改了 data.name 的值后,会在触发执行一次,打印 World 。
我们先看看 reactive 方法的实现~
reactive.js
首先应该明确,我们应该导出一个 reactive 方法,该方法有一个参数 target ,目的就是将 target 变成响应式对象,因此返回值就是一个响应式对象。
reactive 方法基本结构就是如此,给定一个对象,返回一个响应式对象。
其中 isObject 方法用于判断是否是对象,不是对象不需要代理,直接返回即可。
reactive 方法的重点是 Proxy 的第二个参数 handler ,它承载监控对象变化,依赖收集,视图更新等各项重大责任,我们重点来研究这个对象。
handler.js
在 Vue3 中 Proxy 的 handler 主要设置了 get , set , deleteProperty , has , ownKeys 这些属性,即拦截了对象的读取,设置,删除, in 以及 Object.getOwnPropertyNames 方法和 Object.getOwnPropertySymbols 方法。
这里我们偷个懒,暂时就考虑 set 和 get 操作。
handler.get()
get 获取属性比较简单,我们先来看看这个,这里我们用一个方法创建 getHanlder 。
这里推荐使用了 Reflect.get 而并非 target[key] 。
可以发现, Vue3 是在取值的时候才去递归遍历属性的,而非 Vue2 中一开始就递归 data 给每个属性添加 Watcher ,这也是 Vue3 性能提升之一。
handler.set()
同理 set 操作,我们也是用一个方法创建 setHandler 。
Reflect.set 会返回一个 Boolean 值,用于判断属性是否设置成功。
完事后将 handler 导出,然后在 reactive 中引入即可。
测试几组对象貌似没啥问题,其实是有一个坑,这个坑也跟数组有关。
如上例子,如果我们选择代理数组,在 setHandler 中打印其 key 和 value 的话会得到 3 4 , length 4 这两组值:
如果不作处理,那么会导致如果更新视图的话,则会触发两次,这肯定是不允许的,因此,我们需要将区分新增和修改这两种操作。
Vue3 中是通过判断 target 是否存在该属性来区分是新增还是修改操作,需要借助一个工具方法 —— hasOwnProperty 。
这里我们将上述的 createSetter 方法修改如下:
如此一来,我们调 push 方法的时候,就只会触发一次更新了,非常巧妙的避免了无意义的更新操作。
effect.js
光上述构造响应式对象并不能完成响应式的操作,我们还需要一个非常重要的方法 effect ,它会在初始化执行的时候存储跟其有关的数据依赖,当依赖数据发生变化的时候,则会再次触发 effect 传递的函数。
其基本雏形如下,入参是一个函数,还有个可选参数 options 方便后面计算属性等使用,暂时不考虑:
createReactiveEffect 就是为了将 fn 变成响应式函数,监控数据变化,执行 fn 函数,因此该函数是一个高阶函数。
createReactiveEffect 将原来的 fn 转变成一个 reactvieEffect , 并将当前的 effect 挂到全局的 activeEffect 上,目的是为了一会与当前所依赖的属性做好对应关系。
我们必须要将依赖属性构造成 { prop : [effect,effect] } 这种结构,才能保证依赖属性变化的时候,依次去触发与之相关的 effect ,因此,需要在 get 属性的时候,做属性的依赖收集,将属性与 effect 关联起来。
依赖收集 —— track
在获取对象的属性时,会触发 getHandler ,再次做属性的依赖收集,即 Vue2 中的发布订阅。
在 setHandler 中获取属性的时候,做一次 track(target, key) 操作。
整个 track 的数据结构大概是这样
目的就是将 target , key , effect 之间做好对应的关系映射。
打印 targetMap 的结构如下:
**触发更新 —— trigger **
上述已经完成了依赖收集,剩下就是监控数据变化,触发更新操作,即在 setHandler 中添加 trigger 触发操作。
这样一来,获取数据的时候通过 track 进行依赖收集,更新数据的时候再通过 trigger 进行更新,就完成了整个数据的响应式操作。
再回头看看我们先前提到的例子:
控制台会依次打印 Hello ***** effect ***** 以及 World ***** effect ***** , 分别是首次渲染触发跟更新数据重渲染触发,至此功能实现!
整体来说, Vue3 相比于 Vue2 在很多方面都做了调整,数据的响应式只是冰山一角,但是可以看出尤大团队非常巧妙的利用了 Proxy 的特点以及 es6 的数据结构和方法。另外, Composition API 的模式跟 React 在某些程度上有异曲同工之妙,这种设计模式让我们在实际开发使用中更加的方法快捷,值得我们去学习,加油!
最后附上仓库地址 github ,欢迎各位大佬批评斧正~
vue响应式原理是什么?
vue响应式基本原理是基于Object.defineProperty(obj,prop,descriptor),descriptor里面可以定义get和set方法,可以在获取属性值事触发get方法(可以收集依赖),设置属性值时触发set方法(更新依赖)。Vue最独特的特性之一,是其非侵入性的响应式系统。数据模型仅仅是普通的JavaScript对象。而当你修改它们时,视图会进行更新。
vue响应式系统
vue作为一个前端框架,近两年非常的火,虽然它的社区不像react那样繁荣,但它配套的东西都有固定的团队维护,用起来更方便。它是MVVM模型的框架(不熟悉框架模型的同学可以看看阮一峰大神的博客,或者点这里),实现数据的双向绑定,与其他框架相比vue非常的轻量级,另一个重要的特点就是它的响应式系统。
vue2响应式原理总结
vue组件实例化时,会对data属性深度遍历(遇到数组或者对象)为每一个属性添加数据劫持。数据劫持就是使用Object.defineProperty(de fai in pro pu tei)方法添加get/set方法。
在这个过程中会实例化一个Dep类。
1.在get拦截器里触发dep实例的depend方法,进行依赖收集,实质是在dep的实例属性sub数组中添加依赖这个属性的watcher实例。
2.在set拦截器里触发dep实例的notify方法,对收集到的所有依赖派发更新,(watcher的update方法)
vue组件实例化时会实例化一个渲染watcher,渲染watcher实例化过程会做两件事情。
1.创建vnode,在这个过程中,访问了data属性,触发了get方法,完成了依赖收集。
2.触发了子组件的实例化,子组件实例化又会重复上述数据劫持的过程。
这个过程就是对组件树的深度遍历。
结合组件生命周期来看整个过程,父组件会先触发created钩子,子组件后触发created钩子。而子组件mouted钩子会先执行,父组件的mouted钩子后执行。
分步骤记忆
1、实现页面不刷新的原理
2、页面视图刷新的原理
实现页面不刷新
1.hash
2.history
3.abstract:支持所有 JavaScript 运行环境,如 Node.js 服务器端。如果发现没有浏览器的 API,路由会自动强制进入这个模式。
1.hash(哈希模式),#符号后边是浏览器行为,在改变的时候不对页面进行刷新(重新请求URL)(监听hashChange事件)
2.history模式,H5新增了pushState,replaceState连个新API,可以修改历史记录却不会使浏览器刷新页面。
视图更新原理
其原理就是vue的响应式更新dom的原理,m = v
m是数据,也就是在vue-router install时在根组件(root vue component)添加了_route属性,在匹配到对应路由后更新了_route属性值,继而触发了该属性值的渲染watcher,在继而触发dom更新。
两种模式的不同
1.部署时,history模式需要服务端处理所有可能的路径(例如配置nginx的配置文件),防止出现404。哈希模式则不需要。
2.URL表示不同。
v-model指令就是 v-bind:value 和 @input 的语法糖。
它即可以支持原生表单元素,也可以支持自定义组件
在自定义组件中其实际是这样的:
它的实现通过自定义render函数, 缓存了 vnode
Vue 在更新 DOM 时是异步执行的,只要侦听到数据变化,Vue 将开启一个队列,并缓冲在同一事件循环中发生的所有数据变更。
如果同一个 watcher 被多次触发,只会被推入到队列中一次。在缓冲时会去除重复数据避免不必要的计算和 DOM 操作。
$nextTick(cb) 目的是在DOM 更新完成后传入的回调函数再被调用。
vue2vue3响应式原理的介绍就聊到这里吧,感谢你花时间阅读本站内容,更多关于vue的响应原理、vue2vue3响应式原理的信息别忘了在本站进行查找喔。