本篇文章给大家谈谈Vue的响应式原理,以及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 更新完成后传入的回调函数再被调用。
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()
能说说vue的响应式原理吗?
Vue 是一个 MVVM 框架,核心是双向数据绑定,VM(视图模型)是作为 V(视图) 和 M(模型)的桥梁。下面是对 Vue 响应式(双向数据绑定)的理解,如果错误尽请指出,一起交流,共同进步。
Vue响应式原理核心是 数据劫持,采用 ES5 的 object.defineproperty 的 getter 和 setter 方法。从一个例子出发:
首先,在Vue初始化阶段,通过 observer 对 data 中的属性进行递归的劫持,包括 name、job_ undergo、a、b等
在 get阶段也就是初始化视图时,为每一个劫持的属性分配一个 依赖收集器,主要收集当前属性的观察者对象,例子中 name 属性在模板中有两处被使用,那么 name 属性的依赖收集器中就存放两个观察者对象
当点击按钮时,将 name 修改为 lisi 时,会触发 observer 的 setter 函数,将 value 更新为 lisi 最新值,然后通知依赖收集器数据发生了更新。
依赖收集就是发布订阅模式,依赖收集器会通知所有的观察者对象,当前name 属性有两个观察者对象。
观察者对象调用对应的回调函数进行相关的处理和DOM更新
以上是纯响应式原理的分析和总结,下面配一张流程图:
vue数组响应式原理
vue2中Object.defineProperty响应式只对对象有效,对数组无效,所以对数组做额外处理。我们知道,会改变数组本身的方法只有7个:sort, push, pop, slice, splice, shift, unshift,所以可以通过重写这些方法来达到数组响应式
解决方案:
1. 找到数组原型
2. 覆盖那些能够修改数组的更新方法,让他们在修改数组同时,还可以通知更新
3. 将得到的新的原型设置到数组实例原型上
4. 对数组内部元素实现响应式
// 实现数组响应式// 1. 替换数组原型中7个方法constoriginalProto=Array.prototype// 克隆体原数组原型constarrayProto=Object.create(originalProto)// 可修改数组的7个方法 , 'sort'constchangeMethods=['push','pop','shift','unshift','slice','splice','sort']// 2. 在克隆的原型上,覆盖那些能够修改数组的更新方法,让他们在修改数组同时,还可以通知更新changeMethods.forEach(method={arrayProto[method]=function(){// 进行原始操作originalProto[method].apply(this,arguments)// 覆盖操作:增加更新通知console.log(`数组正在执行${method}方法`);}})// 对象响应化functiondefineReactive(obj,key,value){Object.defineProperty(obj,key,{get(){console.log('获取'+key);returnvalue},set(newVal){if(newVal!==value){// console.log(newVal);// console.log(JSON.stringify(obj[key]));console.log(`正在改变${key}值:从${obj[key]}变为${newVal}`)value=newVal}}})}functionobserver(obj){// 不是对象或者为null,不做响应式,结束if(typeofobj!=='object'||obj===null)return;// 如果是数组,修改其实例的原型if(Array.isArray(obj)){// 3. 将得到的新的原型设置到数组实例原型上obj.__proto__=arrayProto// 4. 对数组内的元素,同样进行响应化for(leti=0;iobj.length;i++){// console.log(obj[i]);observer(obj[i])}// 如果是对象}else{Object.keys(obj).forEach(key={console.log(obj,key,obj[key]);defineReactive(obj,key,obj[key])})}}obj=[{a:1},2,7,5,3]observer(obj)obj.push(4)// 数组正在执行push方法obj.pop()// 数组正在执行pop方法obj[0].a=2// 获取a // 正在改变a值:从1变为2obj.sort()// 数组正在执行sort方法console.log(obj);// [ 2, 3, 5, 7, { a: [Getter/Setter] } ]console.log(obj[4].a);// 获取a // 2
链接:
vue2数据响应式原理
vue2响应式原理由 Observer 类, Dep 类和 Watcher 类互相调用实现, Observer 类是把一个普通的object类变成每一层都能相应的类, Dep 类的作用是添加,移除,通知和收集订阅者, Watcher 类是订阅者,主要功能是把当数据改变的时候,去调用回调函数,修改dom节点
那么是怎么实现响应式的呢,首先是一个函数,要先转换为可响应的,那就需要用到 Observer 类
这个 observe 函数就是对 Observer 类做多了一层封装
而 Observer 类是通过 Object.defineProperty 来监控数据的获取和改变的
关键在于 defineReactive 方法,这个方法是对 Object.defineProperty 做了一层封装,并且对对象的每一层做递归调用,实现了每一层都有响应监控
但是是怎么知道现在要保存哪一个 Watcher 实例到订阅者数组里面的呢?其实就是用了这个 Dep.target , Dep.target 相当于 window.target ,全局只有一个,全局也能访问
首先得先讲一讲 Watcher 类,我们先回到上面的index.js,对象要让 Watcher 类进行监听,而 Watcher 有3个参数,第一个是监听的对象,第二个是监听的属性,比如 a.b.c.d ,第三个是属性改变后触发的回调函数
先来讲一下 parsePath ,这个在工具类里,作用是访问 a.b.c.d 这种链式属性
首先是触发了 Watcher 的 get() 方法,把当前实例保存在了 Dep.target 里面
然后在调用 parsePath 获取属性值的过程中,会挨个访问响应对象的属性,就会触发相应的 getter ,我们回到 defineReactive.js ,可以发现这时候相应属性的 getter 就会把 Dep.target 也就是相应的 Watcher 的实例保存在了 Dep 类的订阅者数组里面
最后,在改变属性的时候,相应属性的 setter 就会通知之前已经保存的订阅者数组,遍历触发回调
关于Vue的响应式原理和vue响应式原理简书的介绍到此就结束了,不知道你从中找到你需要的信息了吗 ?如果你还想了解更多这方面的信息,记得收藏关注本站。