Vue的双向数据绑定原理

1.目前双向数据绑定的方法

    发布者-订阅者模式(backbone.js)

        因为本文研究的不是这个,所以不做详细解释。

    脏检查(Angular.js)

        angular只在指定的事件触发时进入脏值检测,例如:DOM事件、XHR响应事件、location变更事件、timer事件、执行$digest()/$apply()

    数据劫持(vue)

        vue是采用数据劫持$发布者-订阅者结合的方式,来做数据绑定,核心就是Object.defineProperty(),劫持各个属性的getter和setter,在数据模型变化的时候,发布消息给订阅者(绑定了数据模型的DOM元素),触发相应的监听回调。

  

2.简单例子实现数据绑定

数据绑定的demo

    obj.name根据输入框值得变化改变,视图会根据obj.name的改变进行更新。这就是简单的实现了view=>model和model=>view的双向数据绑定。这是vue的基本原理,但是在vue 中并不是这么实现的。

3.vue实现数据绑定的能分解步骤

(1)要将视图模型和数据模型绑定起来

(2)视图变化时,触发数据模型变化

(3)数据模型变化时,触发视图变化

4.流程图


vue双向数据绑定流程图

    在实例化一个Vue对象的时候,会传进去一个data对象,之后分成两个进程,一个进程是对挂载目标元素模板里的v-model和{{ }};两个指令进行编译。另一个进程是对传进去的data对象里面的数据进行监听。

    上图中,observe是利用Object.defineProperty()对传入的data对象进行数据监听,在数据改变的时候触发该属性的set方法,更新该属性的值,并发布消息,我(该属性)的值变了。

    compile是编译器,找到vue的指令v-model所在的元素,将data中该属性的值赋给元素的value,并给这个元素添加二级监听器,在元素的值改变的时候,将新值赋给data里面同名属性,这个时候就完成了单向数据绑定,视图 >> 模型。

    那么最终的由模型到视图的更新,依赖于dep和watcher,dep会收集订阅者,就是绑定了data里面属性的元素,在数据更新的时候,会触发该属性的set方法,在set里触发该属性的消息发布通知函数。而Watcher根据收到的数据变化通知,更新相应的数据。

    dep这个东东给大家解释一下,就是data里的每个属性都有一个dep对象,dep对象里可以有很多订阅者(watcher),但是只有一个添加订阅者的方法和一个发布变化通知的方法,就是模板上可以有多处元素绑定data里的同一个属性值,所以dep是依赖于data里面的属性的。

    而Watcher是每个{{ }}有一个,初次编译的时候,会在new的时候自动更新一下模板的数据,等到下次数据改变的时候,由dep通知数据更新,直接调用watcher的update方法,更新模板的绑定数据。

5.new Vue()都干了什么


实例化vue

    上面是正常在构建一个vue项目的时候,实例化一个vue。

Vue类

    实例化一个Vue的两个进程,就是数据监听和模板编译。observe(data, obj)传入两个参数,一个是数据模型data,一个是vue的实例vm。

    而nodeToFragment方法就是识别模板里面的vue指令进行相应的处理,处理之后的template插入到挂载目标元素里。

6.Object.defineProperty(obj, key, options)    

先讲一下这个方法,为下面的数据监听做铺垫。

很简单,该方法接受三个参数,全部都是必填的。参数:       

 obj:目标对象        

 key:属性或者方法的名字       

 options:目标属性所拥有的特性   

主要解释第三个参数        {            

    value:属性的值,            

    writable:布尔值,规定属性是否可重写,          

    configurable:总开关,以第一次设置为准,一旦是false,则其他属性不可设置,            

    enumerbale:决定属性是否可枚举            

    get:重点,后面讲,            

    set:重点,后面讲       

 }    

因为如果没有明确的设置其他值,默认都是false。(可以这么理解)。

configurable    只能设置一次,第二次设置会报错。

writable    在值为true的情况下,才能对该值进行重写修改。

enumerable    定义属性是否可枚举   ,就是能不能被遍历出来。

访问器:(set\get)不能和writable/value同时设置    就是会冲突的意思,set和writable都是设置属性值的,所以会冲突    而get和value都是获取属性值的,所以也会冲突(可以先这么理解)    

so:一山不容二虎,要么用访问器,要么用writable和value.

set    是一个函数,接收一个新值,会在值被重写或修改的时候触发这个函数

get    是一个函数,返回一个值,会在属性被调用的时候触发。

7.数据监听

    利用上面的方法,将data里面所有的属性值遍历一遍,添加上set和get访问器,这样在设置data的属性值的时候,会触发set方法,那么set方法主要有两个作用,一是改变data里面的属性值,二是发出数据变化的通知。


data数据遍历
data处理函数

    上面的方法中,为每一个属性值绑定一个dep对象,初次调用会有Dep.target,当然这是在Watcher里面进行调用,暂且不谈。属性的两个方法,一个get和一个set,数值改变的时候,首先替换掉旧值,再进行数据变化通知,因为变化通知的是订阅这个属性的元素,所以将订阅这个属性的管理对象dep传进去就好了。

通知函数

    通知函数调用了当前dep对象的notify函数,来通知该dep管理的所有订阅者。至此实现了data数据的监听。

dep管理订阅者对象

8.模板编译

    浏览器不认识vue指令,所以要对模板里面的vue指令进行编译,那么先要获取花在目标,将里面的所有节点劫持下来,在新建的文档碎片(documentflagment)里面进行编译,编译完成自后再插入到挂载目标节点。

处理模板函数

    如果挂载目标元素有子节点,那么对第一个子节点进行编译(PS:vue规定template标签里只能有一个子元素哦,所以页面的构建要由一个标签包裹起来,在放入template里面)

模板编译器

    模板编译器函数会判断元素节点是什么类型,表单元素和文本节点分别处理,因为文本节点的value会由用户手动输入,所以要给表单元素添加监听器,根据输入的value改变data里的属性值,再更新到视图上,这是双向的数据流。而文本节点,只要改变data里面的值,节点随着改变就行,只是单向的数据流。

9.数据和节点绑定

因为dep数组里存的全是watcher对象,所以在dep发布变更通知的时候,会调用该watcher的update方法,来更新该watcher对应的节点值。

watcher类该

watcher原型里面的update方法,会在new Watcher()和dep.notify()的时候调用。so:数据监听和模板编译就是通过watcher连接起来的。

    各个函数的位置需要定位好,不然会出现xxx未定义或者xxx不是一个函数。可能我还有没讲明白的地方,我虽然明白,但是不知道怎么讲了,可以评论问我。

    最后附上我写的源码:https://github.com/qianluoluo/vueOrigin

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,847评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,208评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,587评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,942评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,332评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,587评论 1 218
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,853评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,568评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,273评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,542评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,033评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,373评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,031评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,073评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,830评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,628评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,537评论 2 269