vue的简单实现
Posted caoruichun
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了vue的简单实现相关的知识,希望对你有一定的参考价值。
因为vue主要是通过数据劫持来实现的,通过get
、set
来完成数据的读取和更新
这里简单实现data,v-model,computed
1模版
<!DOCTYPE html> <html> <head> <title></title> </head> <body> <div id="app"> <div>{{a.a}}</div> <div>{{c}}</div> <input type="text" v-model="c"> {{hello}} </div> <script src="./mvvm.js"></script> <script type="text/javascript"> let vue = new Vue2({ el:"#app", data:{ a:{a:1}, b:[1,2,3], c:123123 }, computed:{ hello(){ return this.a.a+this.c; } } }) </script> </body> </html>
js
function Vue2(options = {}) { this.$options = options; let data = this._data = this.$options.data; observe(data); // this代理了this._data for (let key in data) { Object.defineProperty(this, key, { enumerable: true, get() { return this._data[key]; }, set(newVal) { this._data[key] = newVal } }) }
initComputed.call(this);//初始化computed
new Compile(options.el, this) } //计算属性的实现 function initComputed(){ let vm = this; let computed = this.$options.computed; Object.keys(computed).forEach(function (k) { Object.defineProperty(vm,k,{
//如果给的是函数那么调取函数,如果是对象那么获取对象的get方法 get:typeof computed[k] === ‘function‘?computed[k]:computed[k].get(), set(){} }) }) } function Compile(el, vm) { // el表示替换的范围 vm.$el = document.querySelector(el); let frament = document.createDocumentFragment();//文案碎片 while (child = vm.$el.firstChild) {//将app中的内容,移入到内存中 frament.appendChild(child) } //查找节点中的{{}} replace(frament); function replace(frament) { Array.from(frament.childNodes).forEach(function (node) { let text = node.textContent; let reg = /\{\{(.*)\}\}/; //判断{{}} if (node.nodeType === 3 && reg.test(text)) { console.log(RegExp.$1)//取出花括号中的变量 let arr = RegExp.$1.split(‘.‘);//[a,a],[b],[c] let val = vm; arr.forEach(function (k) { val = val[k] }) new Watcher(vm,RegExp.$1,function (newVal) { node.textContent = text.replace(/\{\{(.*)\}\}/, newVal) }) // node.textContent = text.replace(/\{\{(.*)\}\}/, val) } //判断v-model if(node.nodeType ===1 /*元素节点*/ ){ let nodeAttrs = node.attributes;//获取属性 console.log(nodeAttrs) Array.from(nodeAttrs).forEach(function (attr) { console.log(attr) let name = attr.name; let exp = attr.value; if(name.indexOf(‘v-‘)==0){ node.value = vm[exp]; } new Watcher(vm,exp,function (newVal) { node.value = newVal; }); node.addEventListener(‘input‘,function (e) { let newVal = e.target.value; vm[exp] = newVal; }) }) } if (node.childNodes) { replace(node) } }); } vm.$el.appendChild(frament) } //观察者 给队形增加Object.defineProperty // 数据劫持 function Observe(data) { let dep = new Dep(); for (let key in data) { let val = data[key]; observe(val); Object.defineProperty(data, key, { enumerable: true, get() { Dep.target&&dep.addSub(Dep.target);//监控值的变化 return val }, set(newVal) { if (newVal === val) { return } val = newVal; observe(newVal) dep.notify()//让所有的watch的update方法执行 } }) } } function observe(data) { if (typeof data !== "object") return; return Observe(data) } //发布订阅 function Dep() { this.subs = [] } Dep.prototype.addSub = function (sub) {//订阅 this.subs.push(sub) } Dep.prototype.notify = function () { this.subs.forEach(sub=>sub.update()) } function Watcher(vm,exp,fn) { this.vm = vm; this.exp = exp; this.fn = fn; Dep.target = this; let val = vm; let arr = exp.split(‘.‘) arr.forEach(function (k) { val = val[k] }) Dep.target = null; } Watcher.prototype.update=function () { let val = this.vm; let arr = this.exp.split(‘.‘); arr.forEach(function (k) { val = val[k] }) this.fn(val) }
以上是关于vue的简单实现的主要内容,如果未能解决你的问题,请参考以下文章