Vue2 双向数据绑定(四)-- 编译器

发布日期:2019-06-11 阅读量:356

1. 编译器

    /**
     * @param el 挂载到的dom节点
     * @param vm 虚拟dom
     */
    function Compile(el, vm) {
        this.el = document.querySelector(el);
        this.vm = vm;
        this.fragment = null; // 页面
        this.init();
    }
    
    Compile.prototype = {
        init: function (){
            if(this.el) { // 节点存在
                this.fragment = this.nodeToFragment(this.el); // 生成页面
                this.compileElement(this.fragment); // 编译页面
                this.el.appendChild(this.fragment); // 将页面渲染到节点
            } else {
                console.log('未设置DOM节点');
                return;
            }
        },
        nodeToFragment: function () {
            var fragment = document.createDocumentFragment(); // 创建虚拟节点
            var child = el.firstChild(); // 孩子节点
            while(child) { // 遍历孩子节点
                fragment.appendChild(child);
                child = el.firstChild();
            }
            return fragment;
        },
        compileElement: function (el) { // 编译DOM元素
            var self = this;
            var childNodes = el.childNodes;
            [].slice.call(childNodes).forEach(function(node) {
                var reg = /{{(.*)}}/; // 匹配{{}}
                var text = node.textContent;
                if (self.isTextNode(node) && reg.test(text)) { // 如果是文本节点
                    self.compileText(node, reg.exec(text)[1]); // ↓找下面的方法编译替换模板数据
                }
                if (node.childNodes && node.childNodes.length) { // 还存在节点就递归
                    self.compileElement(node);
                }
            })
        },
        isTextNode: function(node) {
            return node.nodeType == 3;
        },
        compileText: function(node, exp) {
            var self = this;
            var initText = this.vm[exp];
            this.updateText(node, initText);
            new Watcher(this.vm, exp, function(value) {
                self.updateText(node, value);
            })
        },
        updateText: function(node,value) {
            node.textContent = typeof value == 'undefined' ? '': value;
        },
        isDirective: function(attr) {
            return attr.indexOf('v-') == 0;
        },
        isEventDirective: function(dir) {
            return dir.indexOf('on:') === 0;
        },
        isElementNode: function (node) {
            return node.nodeType == 1;
        }
    }