欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

支持IE6、IE7、IE8等低端浏览器的简化版vue

程序员文章站 2022-07-09 19:59:22
最近研究Vue的底层原理,写了一个简化版的Vue,可以在支持IE6、IE7、IE8等低端浏览器运行。由于低端浏览器不支持对象属性定义,所以设置属性不支持直接赋值,需要调用虚拟机实例的set方法。目前只实现了基础的方法,后续继续完善! ......

最近研究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);
}