(一)vue 模板编译器 compiler

vue的整个架构的流程图

image.png

compiler目的实现解析html里面的vue指令,例如:v-test,v-html,v-model @click等等

//compile工具库
const compileUtil = {
    getValue(expr,vm)
    {
        //根据 字符串 test.name.key 来获取实际对象的 test[name][key] = 123
        return expr.split(".").reduce((data,currentVal)=>{
            //不断递归循环直到 expr.split(".")的数组完毕
            return data[currentVal];
        },vm.$data)
        //vm.$data 是reduce的初始值
    },
    text(node,expr,vm)
    {
        let value;
        console.log(expr)
        if(expr.indexOf('{{')!==-1)
        {
            //replace args[0] = "{{xxx}}" args[1] = xxx
            value = expr.replace(/\{\{(.+?)\}\}/g,(...args)=>{
                console.log(args[1])
                return this.getValue(args[1],vm)
            })
        }
        else
        {
            this.getValue(expr,vm)
        }
        this.updater.textUpdater(node,value)

    },
    html(node,expr,vm)
    {
        const value = this.getValue(expr,vm)
        this.updater.htmlUpdater(node,value)
    },
    model(node,expr,vm)
    {
        const value = this.getValue(expr,vm)
        this.updater.modelUpdater(node,value)

    },
    on(node,expr,vm,detailStr)
    {
        let fn = vm.$options.methods && vm.$options.methods[expr]
        //把功能绑定到 vm执行
        node.addEventListener(detailStr,fn.bind(vm),false)
    },
    bind(node,expr,vm,detailStr)
    {
      node.setAttribute(detailStr,expr)
    },
    //视图更新函数
    updater:{
        textUpdater(node,value)
        {
            node.textContent = value
        },
        htmlUpdater(node,value)
        {
            node.innerHTML = value;
        },
        modelUpdater(node,value)
        {
            //input 里面的value值
            node.value = value;
        }
    }
}

class Compiler
{
    constructor(el,vm)
    {
        this.el = this.isElementNode(el) ? el:document.querySelector(el);
        this.vm = vm;
        // 1. 将预编译的元素节点放入文档碎片对象中,避免DOM频繁的回流与重绘,提高渲染性能
        const fragments = this.node2fragments(this.el)
        //2.编译模板
        this.compile(fragments)
        //3. 追加子元素到根元素
        this.el.appendChild(fragments);


    }

    compile(fragments)
    {
        // 1.获取子节点
        let childNodes = fragments.childNodes
        //2.递归循环编译
        for(var i = 0;i<childNodes.length;i++)
        {
            let child = childNodes[i]

            if(this.isElementNode(child))
            {
                this.compileElement(child)
            }
            else
            {
                this.compileText(child)
            }
            if(child.childNodes && child.childNodes.length)
            {
                this.compile(child)
            }
        }

    }

    compileText(node)
    {
        //解析温饱中的 {{ xxx}}
        const content = node.textContent;
        //(.+)默认是贪婪匹配
        //(.+?)为惰性匹配
        if(/\{\{(.+?)\}\}/.test(content)){
            console.log("testtt")
            console.log(content)
            compileUtil['text'](node,content,this.vm);
        }
    }

    compileElement(node)
    {
        //v-html v-test v-mode v-bind v-on:click
        let attributes = node.attributes
        for(var i =0;i<attributes.length;i++)
        {
            //object
            let attr = attributes[i]
            //-text="msg"  v-html=htmlStr  type="text"  v-model="msg"
            let {name,value} = attr

            if(this.isDirector(name))
            {
                let [,directive] = name.split("-")
                let [compileKey,detailStr] = directive.split(":");
                //根据 属性来处理对应的指令
                compileUtil[compileKey](node,value,this.vm,detailStr);
                // 删除有指令的标签属性 v-text v-html等,普通的value等原生html标签不必删除
                node.removeAttribute('v-' + directive);
            }
            else if(this.isEventName(name))
            {
                let [,detailStr] = name.split("@")
                compileUtil['on'](node,value,this.vm,detailStr)
                node.removeAttribute('@'+detailStr)
            }
            else;
        }

    }

    isEventName(attrName)
    {
      //判断是否@开头 事件绑定
      return attrName.startsWith('@')
    }

    isDirector(attrName)
    {
        //判断是否vue特性标签
        return attrName.startsWith('v-')
    }

    isElementNode(node)
    {
        // nodeType 属性返回节点类型。
        // 如果节点是一个元素节点,nodeType 属性返回 1。
        // 如果节点是属性节点, nodeType 属性返回 2。
        // 如果节点是一个文本节点,nodeType 属性返回 3。
        // 如果节点是一个注释节点,nodeType 属性返回 8。
        //元素节点的nodeType属性等于 1
        return node.nodeType === 1
    }

    node2fragments(el)
    {
        const f = document.createDocumentFragment()
        let firstChild
        while(firstChild = el.firstChild)
        {
            //这里的虚拟节点 append之后 就会把被添加过的节点从el中删除掉
            f.appendChild(firstChild)
        }
        return f;
    }

}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,293评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,604评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,958评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,729评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,719评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,630评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,000评论 3 397
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,665评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,909评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,646评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,726评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,400评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,986评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,959评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,996评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,481评论 2 342

推荐阅读更多精彩内容

  • 33、JS中的本地存储 把一些信息存储在当前浏览器指定域下的某一个地方(存储到物理硬盘中)1、不能跨浏览器传输:在...
    萌妹撒阅读 2,067评论 0 2
  • Vue是一个前端js框架,由尤雨溪开发,是个人项目 Vue近几年来特别的受关注,三年前的时候angularJS霸占...
    6e5e50574d74阅读 550评论 0 0
  • active-class是哪个组件的属性?嵌套路由怎么定义? vue-router模块的router-link组件...
    慢慢慢热型阅读 597评论 0 2
  • 一、了解Vue.js 1.1.1 Vue.js是什么? 简单小巧、渐进式、功能强大的技术栈 1.1.2 为什么学习...
    蔡华鹏阅读 3,311评论 0 3
  • Vue官方文档以下内容作为本人日常学习使用,不作为参考 一、Vue环境搭建以及vue-cli的使用 Vue多页面应...
    好一只帅卤蛋阅读 728评论 0 1