介绍mvvm和mvc
MVVM 是 Model-View-ViewModel 的缩写
Model: 代表数据模型,也可以在Model中定义数据修改和操作的业务逻辑。我们可以把Model称为数据层,因为它仅仅关注数据本身,不关心任何行为.
View: 用户操作界面(UI组件)。当ViewModel对Model进行更新的时候,会通过数据绑定更新到View
ViewModel:业务逻辑层,View需要什么数据,ViewModel要提供这个数据;View有某些操作,ViewModel就要响应这些操作,所以可以说它是Model for View. ViewModel把Model和View关联起来
MVVM作为数据绑定的入口,整合Observer、Compile和Watcher三者,通过Observer来监听自己的model数据变化,通过Compile来解析编译模板指令,最终利用Watcher搭起Observer和Compile之间的通信桥梁,达到数据变化 -> 视图更新;视图交互变化(input) -> 数据model变更的双向绑定效果。
总结:MVVM模式简化了界面与业务的依赖,解决了数据频繁更新。MVVM 在使用当中,利用双向绑定技术,使得 Model 变化时,ViewModel 会自动更新,而 ViewModel 变化时,View 也会自动变化
实现一个简易mvvm
强烈推荐大佬的 gitHub地址(剖析Vue实现原理 - 如何实现双向绑定mvvm)[https://github.com/DMQ/mvvm]
最终效果
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| <div id="app"> <h1>{{msg}}</h1> <span>{{count}}</span> <span>{{person}}</span> </div> <script src="vue.js"></script> <script> let vm = new Vue({ el: '#app', data: { msg: '模拟vue', count: 22, person: 'cpp' } }) vm.person = '陈大鹏' </script>
|
vue.js
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 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199
|
class Vue { constructor(options = {}) { this.$options = options || {} this.$data = options.data || {} this.$el = typeof options.el === 'string' ? document.querySelector(options.el) : options.el; new Observer(this.$data) new Compiler(this) } _proxyData(data) { Object.keys(data).forEach(key => { Object.defineProperty(this, key, { get() { return data[key] }, set(val) { if (val === data[key]) { return } data[key] = val } }) }) } }
class Observer { constructor(data) { this.walk(data) } walk(data) { if (!data || typeof data !== 'object') { return } Object.keys(data).forEach(key => { this.defineReactive(data, key, data[key]); this.walk(data[key]) }) } defineReactive(obj, key, val) { let dep = new Dep() let that = this; Object.defineProperty(obj, key, { enumerable: true, configurable: true, get: function reactiveGetter() { console.log('Dep.target 当前的wtacher 才能收集依赖') Dep.target && dep.addSub(Dep.target) return val }, set: function reactiveSetter(newValue) { if (val === newValue) { return } that.walk(newValue); dep.notify() val = newValue } }) } }
class Compiler { constructor(vm) { this.el = vm.$el; this.vm = vm; this.compile(this.el) } compile(el) { let childNodes = el.childNodes Array.from(childNodes).forEach((node) => { if (this.isTextNode(node)) { this.compileText(node) } else if (this.isElementNode(node)) { this.compileElement(node) } if (node && node.childNodes && node.childNodes.length) { this.compile(node) } }) } compileElement(node) { Array.from(node.attributes).forEach((attr) => { let attrName = attr.name if (this.isDirective(attrName)) { attrName = attrName.substr(2) let key = attr.value this.update(node, key, attrName) } }) } update(node, key, attrName) { this[attrName + 'Updater'] && this[attrName + 'Updater'](node, this.vm.$data[key], key) } textUpdater(node, value, key) { node.textContent = value new Watcher(this.vm.$data, key, (newValue) => { node.textContent = newValue }) } modelUpdater (node, value, key) { node.value = value; new Watcher(this.vm.$data, key, (newValue) => { node.value = newValue }) node.addEventListener('input', () => { this.vm.$data[key] = node.value }) } compileText(node) { let reg = /\{\{(.+?)\}\}/; let val = node.textContent; if (reg.test(val)) { let key = RegExp.$1.trim() node.textContent = val.replace(reg, this.vm.$data[key]); new Watcher(this.vm.$data, key, (val) => { node.textContent = val }) } }
isDirective(attrName) { return attrName.startsWith('v-') } isTextNode(node) { return node.nodeType === 3 } isElementNode(node) { return node.nodeType === 1 } }
class Dep { constructor() { this.subs = [] } addSub(sub) { console.log('addSub 开始收集依赖', sub) this.subs.push(sub) } notify() { this.subs.forEach((sub) => { sub.update() }) } }
class Watcher { constructor(vm, key, cb) { this.vm = vm; this.key = key; this.cb = cb; this.value = this.get() } get() { Dep.target = this var value = this.vm[this.key] Dep.target = null return value } update() { var value = this.get() var oldValue = this.value if (value !== oldValue) { this.value = value this.cb(value) } } }
|
参考