支持IE6、IE7、IE8等低端浏览器的简化版vue
程序人生♨︎ 人气:0最近研究Vue的底层原理,写了一个简化版的Vue,可以在支持IE6、IE7、IE8等低端浏览器运行。由于低端浏览器不支持对象属性定义,所以设置属性不支持直接赋值,需要调用虚拟机实例的set方法。目前只实现了基础的方法,后续继续完善!
index.html
<!DOCTYPE html> <html> <head> <title>简化版Vue</title> <script> window.onerror=function(){ return true; } </script> </head> <body> <hr /> <div id="simpleVue"> <button v-on:click="copy">戳我</button> <div> <textarea v-model="name"></textarea> <div v-text="name"></div> </div> <div> <select v-model="name"> <option value="name1" selected>name1</option> <option value="name2">name2</option> <option value="name3">name3</option> </select> </div> <hr> <button v-on:click="show">显示/隐藏</button> <div v-if="isShow"> <input type="text" style="width: 300px" v-model="webSite"> <div v-text="webSite"></div> </div> </div> <script src="vmm.js"></script> <script> var vm = new VMM({ el: '#simpleVue', data: { name: '测试', webSite: 'https://github.com/steezer', isShow: true }, methods: { copy: function(){ vm.set('name', this.name +'测试'); }, show: function(){ vm.set('isShow', !this.isShow); } } }); </script> </body> </html>
vmm.js
function VMM(options){ /** * 订阅器构造 用来接收属性值的相关数据的变化通知 从而更新视图 * * @param {Object} vm 虚拟机对象 * @param {HTMLElement} el Node节点 * @param {String} attr 属性名称 * @param {Object} val 属性值 */ function Watcher(vm, el, attr, val){ this.vm = vm; this.el = el; this.attr = attr; this.val = val; /** * 将收到的新的数据更新在视图中 */ this.update = function() { if (this.vm.$data[this.val] === true) { this.el.style.display = 'block'; } else if (this.vm.$data[this.val] === false) { this.el.style.display = 'none'; } else { this.el[this.attr] = this.vm.$data[this.val]; } } // 初始化订阅器时更新一下视图 this.update(); } /** * 获取对象 * * @param {Object|String} id * @returns Object */ function getElem(id){ if(typeof(id)=='object'){ return id; } var target=id+'', prefix=target.substr(0,1), target=target.substr(1); if(prefix=='#'){ return document.getElementById(target); } if(prefix=='.'){ return document.getElementsByClassName(target); } return document.getElementsByTagName(target); } function getAttr(elem, name) { var node = elem.getAttributeNode(name); if (node && node.specified) { return node.nodeValue; } else { return undefined; } } function addEvent(node, type, handle){ if(document.addEventListener){ node.addEventListener(type, handle, false); }else{ node.attachEvent('on'+type, function(){ handle.call(node, arguments); }); }; } this.$el = getElem(options.el); this.$data = options.data; this.$methods = options.methods; this.oWatcherObj = {}; // 获取属性 this.get=function(key){ return this.$data[key]; } // 设置属性 this.set=function(key, newVal){ var value=this.$data[key]; if (newVal !== value) { this.$data[key] = newVal; if(typeof(this.oWatcherObj[key])!="undefined"){ var watchers=this.oWatcherObj[key]; for(var i=0; i< watchers.length; i++){ watchers[i].update(); } } } } /** * 节点DOM解析器 */ this.compile=function(el) { var nodes = el.children, $this=this, addWatcher=function(node, attr, val){ if(typeof($this.oWatcherObj[val])=='undefined'){ $this.oWatcherObj[val]=[]; } $this.oWatcherObj[val].push(new Watcher($this, node, attr, val)); }; // 迭代同级所有节点 var values=[]; for(var k in el){ values.push(k) } for (var i = 0; i < nodes.length; i++) { var node = nodes[i],val; if (node.children.length > 0) { this.compile(node); // 递归所有子节点 } // 点击事件 val=getAttr(node, 'v-on:click'); if (val) { if(typeof($this.$methods[val])=="function"){ addEvent(node, 'click', (function(val){ return function(e){ $this.$methods[val].call($this.$data, e); } })(val)); } } // IF指令 val=getAttr(node, 'v-if'); if (val) { addWatcher(node, "", val); } // Model val=getAttr(node, 'v-model'); if (val) { var event=node.tagName.match(/select/i) ? 'change' : ('oninput' in node ? 'input' : 'propertychange'); addWatcher(node, "value", val); addEvent(node, event, (function(i, val){ return function(e){ $this.set(val, nodes[i].value); } })(i, val)); } // Text val=getAttr(node, 'v-text'); if (val) { addWatcher(node, "innerText", val); } // Html val=getAttr(node, 'v-html'); if (val) { addWatcher(node, "innerHTML", val); } } } // 节点解析 this.compile(this.$el); }
加载全部内容