Open Genzhen opened 2 years ago
每日一题会在下午四点在交流群集中讨论,五点小程序中更新答案 欢迎大家在下方发表自己的优质见解 二维码加载失败可点击 小程序二维码
每日一题会在下午四点在交流群集中讨论,五点小程序中更新答案 欢迎大家在下方发表自己的优质见解
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title>JS Bin</title> </head> <body> <div id="app"> <input v-model="name" v-on:click="hello" type="text" /> <input v-model="age" type="text" /> <h3>{{name}}'s age is: {{age}}</h3> </div> </body> </html>
// MVVM(Model-View-ViewModel) 单项绑定 function observe(data) { if (!data || typeof data !== "object") return; for (var key in data) { let val = data[key]; let sub = new Subject(); Object.defineProperty(data, key, { enumerable: true, configurable: true, get: function () { console.log("get function in observer fun"); console.log(val); if (currentObserver) { console.log("currentOb exist" + currentObserver); currentObserver.subscribeTo(sub); } return val; }, set: function (newVal) { console.log("set function in observer fun"); val = newVal; sub.notify(); }, }); if (typeof val === "object") { observe(val); } } } let currentObserver = null; let id = 0; class Subject { constructor() { this.id = id++; this.observers = []; } addObserver(observer) { console.log("addObserver fun in class subject"); this.observers.push(observer); } removerObserver(observer) { console.log("removeOb fun in class subject"); var index = this.observers.indexOf(observer); if (index > -1) { this.observers.splice(index, 1); } } notify() { console.log("notify fun in class subject"); this.observers.forEach((observer) => { observer.update(); }); } } class Observer { constructor(vm, key, callback) { this.subjects = {}; this.vm = vm; this.key = key; this.callback = callback; this.value = this.getValue(); } getValue() { console.log("getValue fun in class observer"); currentObserver = this; // console.log('bug start, print vm,vm.data,key'); // console.log(this); // console.log(this.vm); // console.log(this.vm.$data); // console.log(this.key); let value = this.vm.$data[this.key]; currentObserver = null; return value; } update() { console.log("update fun in class observer"); var oldVal = this.value; var newVal = this.getValue(); if (oldVal !== newVal) { this.value = newVal; this.callback.bind(this.vm)(newVal, oldVal); } } subscribeTo(subject) { console.log("subscribeto fun in class observer"); if (!this.subjects[subject.id]) { console.log("subscribe to... ", subject); subject.addObserver(this); this.subjects[subject.id] = subject; } } } class mvvm { constructor(opts) { this.init(opts); observe(this.$data); new Compile(this); } init(opts) { console.log("init fun in mvvm class"); this.$ele = document.querySelector(opts.ele); this.$data = opts.data || {}; this.methods = opts.methods || {}; for (let key in this.methods) { this.methods[key] = this.methods[key].bind(this); } for (let key in this.$data) { Object.defineProperty(this, key, { enumerable: true, configurable: true, get: () => { return this.$data[key]; }, set: (newVal) => { this.$data[key] = newVal; }, }); } } } class Compile { constructor(vm) { this.vm = vm; this.node = vm.$ele; this.compile(); } compile() { console.log("compile fun in class Compile"); this.traverse(this.node); } traverse(node) { console.log("traverse fun in class Compile"); if (node.nodeType === 1) { this.compileNode(node); node.childNodes.forEach((childNode) => { this.traverse(childNode); }); } else if (node.nodeType === 3) { this.renderText(node); } } // 处理指令 compileNode(node) { let attrsArr = Array.from(node.attributes); attrsArr.forEach((attr) => { if (this.isModel(attr.name)) { this.bindModel(node, attr); } else if (this.isHandle(attr.name)) { this.bindHandle(node, attr); } }); } bindModel(node, attr) { let key = attr.value; node.value = this.vm.$data[key]; new Observer(this.vm, key, function (newVal) { node.value = newVal; }); node.oninput = (e) => { this.vm.$data[key] = e.target.value; }; } bindHandle(node, attr) { let startIndex = attr.name.indexOf(":") + 1; let endIndex = attr.name.length; let eventType = attr.name.substring(startIndex, attr.name.length); let method = attr.value; node.addEventListener(eventType, this.vm.methods[method]); } // 判断指令 isModel(attrName) { return attrName === "v-model"; } isHandle(attrName) { return attrName.indexOf("v-on") > -1; } // 渲染单变量 renderText(node) { console.log("render fun in class Compile"); let reg = /{{(.+?)}}/g; let match; while ((match = reg.exec(node.nodeValue))) { let raw = match[0]; let key = match[1].trim(); node.nodeValue = node.nodeValue.replace(raw, this.vm.$data[key]); new Observer(this.vm, key, function (newVal, oldVal) { node.nodeValue = node.nodeValue.replace(oldVal, newVal); }); } } } let testMvvm = new mvvm({ ele: "#app", data: { name: "fejavu", age: 23, }, methods: { hello: function () { console.log("testmvvm start"); console.log(this); console.log(this.vm); // console.log(this) alert("hello! " + this.name); }, }, });
扫描下方二维码,收藏关注,及时获取答案以及详细解析,同时可解锁800+道前端面试题。
简单实现参考