Vue
官网有一段这样的介绍:当你把一个普通的JavaScript
对象传给Vue
实例的data
选项,Vue
将遍历此对象所有的属性,并使用Object.defineProperty
把这些属性全部转为getter/setter
。Object.defineProperty
是ES5
中一个无法shim
的特性,这也就是为什么Vue
不支持 IE8 以及更低版本浏览器。
通过这一段的介绍不难可以得出,Vue是通过Object.defineProperty
对实例中的data
数据做了挟持并且使用Object.defineProperty
的getter/setter
并对其进行处理之后完成了数据的与视图的同步。
这张图应该不会很陌生,熟悉Vue
的同学如果仔细阅读过Vue
文档的话应该都看到过。猜想一下Vue
使用Object.defineProperty
做为ViewModel
,对数据进行挟持之后如果View
和Model
发生变化的话,就会通知其相对应引用的地方进行更新处理,完成视图的与数据的双向绑定。
下面举个例子:
html:
1 |
|
javaScript:
1 2 3 4 5 6 7 8 9 10 |
|
通过上面的代码使用Object.defineProperty
对Obj
对象中的name
属性进行了挟持,一旦该属性发生了变化则会触发set
函数执行,做出响应的操作。
扯了这么多,具体说一下Vue
实现的原理。
Observer
,能够对数据对象的所有属性进行监听,如有变动可拿到最新值并通知订阅者。Compile
,对每个元素节点的指令进行扫描和解析,根据指令模板替换数据,以及绑定相应的更新函数。Watcher
,作为连接Observer
和Compile
的桥梁,能够订阅并收到每个属性变动的通知,执行指令绑定的相应回调函数,从而更新视图。MVVM
入口函数,整合以上三者,实现数据响应。接下来的文章将沿着这个思路一步一步向下进行,以便完成一个简单的Vue
类,完成数据与视图的实时更新。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
|
以上代码则是需要完成的功能,保证所有功能全部都能实现。
首先我们要考虑的是,要创建一个Vue
的类,该类接收的是一个options
的对象,也就是我们在实例化Vue
的时候需要传递的参数。
1 2 3 4 5 6 7 8 |
|
通过上面的代码可以看出了,为什么我们可以在Vue
实例上通过this.$data
拿到我们所写的data
数据。
对数据已经进行了缓存之后,接下来要做的事情就是对数据进行观察,达到数据变化之后能够做出对虚拟Dom
的操作。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 |
|
我们对data
数据中的每一项都进行了数据挟持,可是然而并没有什么卵用啊,我们并没有对相对应的虚拟dom
进行数据改变,当然我们肯定是不能把我们的需要更改的虚拟dom
操作写在这里,然而在Vue
中对其Dom
进行了特殊的处理,慢慢的向下看。
想要做数据响应要做一个做具体更新的类何以用来管理这些观察者的类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
|
Dep.target = this
上面这段代码一定要注意,是向Dep
类中添加了一个静态属性。
主要用来解析各种指令,比如v-modal
,v-on:click
等指令。然后将模版中的变量替换成数据,渲染view
,将每个指令对应的节点绑定更新函数,添加监听数据的订阅者,一旦数据发生变动,收到通知,更新视图。
简单说下双向绑定,双向绑定原理,在编译的时候可以解析出v-model在做操作的时候,在使用v-model元素上添加了一个事件监听(input),把事件监听的回调函数作为事件监听的回调函数,如果input发生变化的时候把最新的值设置到vue的实例上,因为vue已经实现了数据的响应化,响应化的set函数会触发界面中所有依赖模块的更新,然后通知哪些model做依赖更新,所以界面中所有跟这个数据有管的东西就更新了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 |
|
其实Compile
整个编译过程,就是在做一个依赖收集的工作,然Vue
知道每一个指令是做什么的。并做出对应的更新处理。
Vue整体的编译过程,因为vue所编写的指令html无法进行识别,通过编译的过程可以进行依赖收集,依赖收集以后把data中的数据和视图进行了关联,产生了依赖关系,如果以后数据模型发生变化我们可以通过这些依赖通知这些视图进行更新,这是执行编译的目的,就可以做到数据模型驱动视图变化。
参考文章:
vue中的双向数据绑定详解
Vue双向绑定实现
感兴趣的朋友可以使用在线HTML/CSS/JavaScript代码运行工具:http://tools.jb51.net/code/HtmlJsRun测试上述代码运行效果。
更多关于JavaScript相关内容感兴趣的读者可查看本站专题:《javascript面向对象入门教程》、《JavaScript错误与调试技巧总结》、《JavaScript数据结构与算法技巧总结》、《JavaScript遍历算法与技巧总结》及《JavaScript数学运算用法总结》
希望本文所述对大家JavaScript程序设计有所帮助。