vue双向绑定原理

vuejs双向绑定的实现:

双向绑定是指数据到视图的绑定和视图到数据的绑定。

 

 

简单回答:

 

双向绑定 是数据到视图和视图到数据,
1.视图到数据就是监听事件,比如input框使用了v-model,会被内部解析为:value 和 @change 其中对input框的@change事件会监听dom事件,当输入框内容变化时数据变化
2.数据到视图是一个响应式更新的过程,vue在初始化的时候回将data中的内容设置为响应式,设置getter和setter,当页面渲染watcher执行render方法的时候,会触发getter,收集依赖,
当数据改变的时候,会触发setter,触发watcher的update方法,进而会引起重新render和重新渲染DOM

 

 

 

 

========================================================================================

稍微复杂的回答:

 

视图变化引发数据变化

直接处理对应的event handler,该更改数据变化就可以了,

主要是通过vue的指令,v-on @来注册事件,在模板解析的时候,事件会保存在VNode对象中,

虚拟DOM在patch的过程中,会根据不同的时机触发不同的钩子函数。

事件绑定updateDOMListeners的处理逻辑设置在了create与update钩子函数,也就是说在patch的过程中,当一个DOM元素被创建或更新时,都会触发事件绑定相关处理逻辑。

create与update钩子都执行updateDOMListeners函数,

调用updateListeners方法,对比on与oldOn,然后根据结果调用add或remove方法,

add方法内部就是浏览器的node.addEventListener

 

 

 

 

数据变化引发视图变化,首先我们要侦测数据的变化, 

vue内部有一个observe函数,用于将数据处理成响应式数据,

(会把data属性中的数据处理成响应式数据)

对于对象的每个key,都会使用defineReactive函数处理,每个key都会有一个

Dep类实例dep(内部有一个数组)来保存他们的依赖watcher, 

使用Object.defineProperty设置这些key值上数据的getter和setter,

对于对象上的一个key,

当getter被触发的时候

会向dep中添加依赖, 依赖是指Watcher类的实例watcher,当setter被触发的时候,会向watcher发送通知触发watcher内部的内容。

 

 

对于对象,使用Object.defineProperty来设置getter和setter

 (在defineReactive函数内部,参数是obj,key,value…会在内部先实例化一个new Dep然后调用Object.defineProperty,会引用到初始化的dep实例,在get的时候调用dep.depend(),在set的时候调用dep.notify()) 

 

对于数组,使用数组拦截器覆盖原型上方法来获取对数组的操作。

数组收集依赖的方式和对象一样,都是在getter中收集,因为数组的位置一定也是在一个对象上,window.arr, this.arr … …

与对象用setter监测变化不同,数组使用拦截器监测了变化,

我们必须把dep保存在拦截器能触发的地方,所以保存在了observer实例上,

(所以,数组的dep在observer实例上) (!对象的key的dep是在Observer类对某一个key执行defineReactive函数时创建的一个dep, 是在 闭包中的,不能直接拿到的。 20220306补 https://github.com/vuejs/vue/blob/dev/src/core/observer/index.js 这里observer内部的this.dep是为数组预留的 )

 

初始化observer实例的时候,即Observer类的内部的constructor(value)中,新增了def(value,’__ob__’,this),

此后,value的__ob__属性就对应了其observer实例, 在数组应用拦截器时候,直接调用this.__ob__ 就能获取到observer实例,

然后调用ob.dep.notify() 来通知依赖向依赖发送消息。

 

 

 

==================================================================== 

 

当执行let vm = new Vue(options)的时候,

1.会执行内部的_init方法,其中执行到initState方法,

会使用observe函数处理vm.data,将data处理成响应式数据。

 

2.如果options中有el选项,会执行$mount方法,执行mountComponent函数

在mountComponent函数内部 new Watcher(vm, updateComponent,noop..

 

updateComponent是一个函数,

watcher的第二个参数可以是一个表达式也可以是一个函数

如果是一个函数,会将getter设置为这个函数,并将watcher实例value初始值设置为函数执行的结果

 

 

posted @ 2020-05-11 15:15  hh9515  阅读(163)  评论(0)    收藏  举报