Open YBFACC opened 4 years ago
通过Object.defineProperty劫持属性。
通过订阅-发布模式来修改dom节点。
初始化流程:
运行流程:
代码参考来自vue 的双向绑定原理及实现
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>self-vue</title> </head> <style> #name { text-align: center; } </style> <body> <h1 id="name">{{name}}</h1> </body> <script> function SelfVue(data, el, exp) { this.data = data observe(data) el.innerHTML = this.data[exp] // 初始化模板数据的值 new Watcher(this, exp, function (value) { el.innerHTML = value }) return this } </script> <script>function Observer(data) { this.data = data this.walk(data) } Observer.prototype = { walk: function (data) { var self = this Object.keys(data).forEach(function (key) { self.defineReactive(data, key, data[key]) }) }, defineReactive: function (data, key, val) { var dep = new Dep() Object.defineProperty(data, key, { enumerable: true, configurable: true, get: function () { if (Dep.target) { dep.addSub(Dep.target) } return val }, set: function (newVal) { if (newVal === val) { return } val = newVal dep.notify() } }) } } function observe(value, vm) { if (!value || typeof value !== 'object') { return } return new Observer(value) } function Dep() { this.subs = [] } Dep.prototype = { addSub: function (sub) { this.subs.push(sub) }, notify: function () { this.subs.forEach(function (sub) { sub.update() }) } } Dep.target = null </script> <script> function Watcher(vm, exp, cb) { this.cb = cb; this.vm = vm; this.exp = exp; this.value = this.get(); // 将自己添加到订阅器的操作 } Watcher.prototype = { update: function () { this.run(); }, run: function () { var value = this.vm.data[this.exp]; var oldVal = this.value; if (value !== oldVal) { this.value = value; this.cb.call(this.vm, value, oldVal); } }, get: function () { Dep.target = this; // 缓存自己 var value = this.vm.data[this.exp] // 强制执行监听器里的get函数 Dep.target = null; // 释放自己 return value; } }; </script> <script> var ele = document.querySelector('#name'); var selfVue = new SelfVue({ name: 'hello world' }, ele, 'name'); window.setTimeout(function () { console.log('name值改变了'); selfVue.data.name = 'canfoo'; }, 2000); </script> </html>
vue 的双向绑定原理及实现
双向绑定
通过Object.defineProperty劫持属性。
通过订阅-发布模式来修改dom节点。
初始化流程:
运行流程:
代码参考来自vue 的双向绑定原理及实现
参考
vue 的双向绑定原理及实现