手写vue双向绑定数据
Posted ServerSocket
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了手写vue双向绑定数据相关的知识,希望对你有一定的参考价值。
来一张原理图:
实现思路:
(1)绑定data 种的数据,为每个数据添加指令。通过Object,defineProperty() 来通知属性是否更改
(2) 找到每个DOM节点的指令。绑定事件。并绑定watcher
(3) 实现DOM事件改变之后, 响应data数据,实现视图更新
<!DocType> <html> <title>vue 的双向绑定事件</title> <body id="app"> <input type="text" v-model="number"/> <span v-bind="number"></span> <input type="text" v-model="age"/> <span v-bind="age"></span> </body> <script> function Vue (options) { this._init(options); } Vue.prototype._init = function (options) { this.$data = options.data; this.$methods = options.data.methods; this.$el = document.querySelector(options.el); this.$methods = options.methods; this.$key = \'\'; this._binding = {}; // 观测数据 this._observer(this.$data); this._complie(this.$el); // this._test(this.$data); } // 观测数据 Vue.prototype._observer = function (obj) { var value; let _this = this; for (key in obj) { if (obj.hasOwnProperty(key)) { this._binding[key] = { _directives: [] }; value = obj[key]; if (typeof value === \'object\') { this._observer(value); } Object.defineProperty(this.$data, key, { enumerable: true, configurable: true, get: function () { console.log(`获取${value}`, key); return value; }, set: function (newVal) { console.log(\'key:\', key, _this.$key); if (value !== newVal) { value = newVal; _this._binding[_this.$key]._directives.forEach(function (item, index) { item.update(); }) } } }) } } } // 为DOM节点添加指令事件 Vue.prototype._complie = function (root) { var _this = this; var nodes = root.children; for (var i = 0; i < nodes.length; i++) { var node = nodes[i]; if (node.children.length) { this._complie(node); } if (node.hasAttribute(\'v-click\')) { node.onclick = (function () { var attrVal = nodes[i].getAttribute(\'v-click\'); return _this.$methods[attrVal].bind(_this.$data); })(); } if (node.hasAttribute(\'v-model\') && (node.tagName == \'INPUT\' || node.tagName == \'TEXTAREA\')) { node.addEventListener(\'input\', (function(key) { var attrVal = node.getAttribute(\'v-model\'); _this._binding[attrVal]._directives.push(new Watcher( \'input\', node, _this, attrVal, \'value\' )) return function() { _this.$key = attrVal _this.$data[attrVal] = nodes[key].value; } })(i)); } if (node.hasAttribute(\'v-bind\')) { var attrVal = node.getAttribute(\'v-bind\'); _this._binding[attrVal]._directives.push(new Watcher( \'text\', node, _this, attrVal, \'innerHTML\' )) } } } function Watcher(name, el, vm, exp, attr) { this.name = name; //指令名称,例如文本节点,该值设为"text" this.el = el; //指令对应的DOM元素 this.vm = vm; //指令所属myVue实例 this.exp = exp; //指令对应的值,本例如"number" this.attr = attr; //绑定的属性值,本例为"innerHTML" this.update(); } // 更新数据 Watcher.prototype.update = function () { this.el[this.attr] = this.vm.$data[this.exp]; } // 测试 Vue.prototype._test = function($data) { var a = $data.number; $data.number = 32; } window.onload = function () { var app = new Vue({ el: \'#app\', data: { number: 12, age: 444 }, methods: {} }) } </script> </html>
以上是关于手写vue双向绑定数据的主要内容,如果未能解决你的问题,请参考以下文章