(一)vue 模板編譯器 compiler

vue的整個(gè)架構(gòu)的流程圖

image.png

compiler目的實(shí)現(xiàn)解析html里面的vue指令,例如:v-test,v-html,v-model @click等等

//compile工具庫(kù)
const compileUtil = {
    getValue(expr,vm)
    {
        //根據(jù) 字符串 test.name.key 來(lái)獲取實(shí)際對(duì)象的 test[name][key] = 123
        return expr.split(".").reduce((data,currentVal)=>{
            //不斷遞歸循環(huán)直到 expr.split(".")的數(shù)組完畢
            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執(zhí)行
        node.addEventListener(detailStr,fn.bind(vm),false)
    },
    bind(node,expr,vm,detailStr)
    {
      node.setAttribute(detailStr,expr)
    },
    //視圖更新函數(shù)
    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. 將預(yù)編譯的元素節(jié)點(diǎn)放入文檔碎片對(duì)象中萍诱,避免DOM頻繁的回流與重繪悬嗓,提高渲染性能
        const fragments = this.node2fragments(this.el)
        //2.編譯模板
        this.compile(fragments)
        //3. 追加子元素到根元素
        this.el.appendChild(fragments);


    }

    compile(fragments)
    {
        // 1.獲取子節(jié)點(diǎn)
        let childNodes = fragments.childNodes
        //2.遞歸循環(huán)編譯
        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;
        //(.+)默認(rèn)是貪婪匹配
        //(.+?)為惰性匹配
        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(":");
                //根據(jù) 屬性來(lái)處理對(duì)應(yīng)的指令
                compileUtil[compileKey](node,value,this.vm,detailStr);
                // 刪除有指令的標(biāo)簽屬性 v-text v-html等,普通的value等原生html標(biāo)簽不必刪除
                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)
    {
      //判斷是否@開(kāi)頭 事件綁定
      return attrName.startsWith('@')
    }

    isDirector(attrName)
    {
        //判斷是否vue特性標(biāo)簽
        return attrName.startsWith('v-')
    }

    isElementNode(node)
    {
        // nodeType 屬性返回節(jié)點(diǎn)類(lèi)型裕坊。
        // 如果節(jié)點(diǎn)是一個(gè)元素節(jié)點(diǎn)包竹,nodeType 屬性返回 1。
        // 如果節(jié)點(diǎn)是屬性節(jié)點(diǎn), nodeType 屬性返回 2籍凝。
        // 如果節(jié)點(diǎn)是一個(gè)文本節(jié)點(diǎn)周瞎,nodeType 屬性返回 3。
        // 如果節(jié)點(diǎn)是一個(gè)注釋節(jié)點(diǎn)饵蒂,nodeType 屬性返回 8声诸。
        //元素節(jié)點(diǎn)的nodeType屬性等于 1
        return node.nodeType === 1
    }

    node2fragments(el)
    {
        const f = document.createDocumentFragment()
        let firstChild
        while(firstChild = el.firstChild)
        {
            //這里的虛擬節(jié)點(diǎn) append之后 就會(huì)把被添加過(guò)的節(jié)點(diǎn)從el中刪除掉
            f.appendChild(firstChild)
        }
        return f;
    }

}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市退盯,隨后出現(xiàn)的幾起案子彼乌,更是在濱河造成了極大的恐慌,老刑警劉巖渊迁,帶你破解...
    沈念sama閱讀 217,826評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件慰照,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡琉朽,警方通過(guò)查閱死者的電腦和手機(jī)毒租,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,968評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)漓骚,“玉大人蝌衔,你說(shuō)我怎么就攤上這事◎蝓澹” “怎么了噩斟?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,234評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)孤个。 經(jīng)常有香客問(wèn)我剃允,道長(zhǎng),這世上最難降的妖魔是什么齐鲤? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,562評(píng)論 1 293
  • 正文 為了忘掉前任斥废,我火速辦了婚禮,結(jié)果婚禮上给郊,老公的妹妹穿的比我還像新娘蔗崎。我一直安慰自己弄企,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,611評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著舌菜,像睡著了一般。 火紅的嫁衣襯著肌膚如雪先嬉。 梳的紋絲不亂的頭發(fā)上泵肄,一...
    開(kāi)封第一講書(shū)人閱讀 51,482評(píng)論 1 302
  • 那天,我揣著相機(jī)與錄音焕蹄,去河邊找鬼逾雄。 笑死,一個(gè)胖子當(dāng)著我的面吹牛腻脏,可吹牛的內(nèi)容都是我干的鸦泳。 我是一名探鬼主播,決...
    沈念sama閱讀 40,271評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼迹卢,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼辽故!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起腐碱,我...
    開(kāi)封第一講書(shū)人閱讀 39,166評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤誊垢,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后症见,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體喂走,經(jīng)...
    沈念sama閱讀 45,608評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,814評(píng)論 3 336
  • 正文 我和宋清朗相戀三年谋作,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了芋肠。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,926評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡遵蚜,死狀恐怖帖池,靈堂內(nèi)的尸體忽然破棺而出奈惑,到底是詐尸還是另有隱情,我是刑警寧澤睡汹,帶...
    沈念sama閱讀 35,644評(píng)論 5 346
  • 正文 年R本政府宣布肴甸,位于F島的核電站,受9級(jí)特大地震影響囚巴,放射性物質(zhì)發(fā)生泄漏原在。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,249評(píng)論 3 329
  • 文/蒙蒙 一彤叉、第九天 我趴在偏房一處隱蔽的房頂上張望庶柿。 院中可真熱鬧,春花似錦秽浇、人聲如沸浮庐。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,866評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)兔辅。三九已至,卻和暖如春击喂,著一層夾襖步出監(jiān)牢的瞬間维苔,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,991評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工懂昂, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留介时,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,063評(píng)論 3 370
  • 正文 我出身青樓凌彬,卻偏偏與公主長(zhǎng)得像沸柔,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子铲敛,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,871評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容

  • 33褐澎、JS中的本地存儲(chǔ) 把一些信息存儲(chǔ)在當(dāng)前瀏覽器指定域下的某一個(gè)地方(存儲(chǔ)到物理硬盤(pán)中)1、不能跨瀏覽器傳輸:在...
    萌妹撒閱讀 2,083評(píng)論 0 2
  • Vue是一個(gè)前端js框架伐蒋,由尤雨溪開(kāi)發(fā)工三,是個(gè)人項(xiàng)目 Vue近幾年來(lái)特別的受關(guān)注,三年前的時(shí)候angularJS霸占...
    6e5e50574d74閱讀 552評(píng)論 0 0
  • active-class是哪個(gè)組件的屬性先鱼?嵌套路由怎么定義俭正? vue-router模塊的router-link組件...
    慢慢慢熱型閱讀 598評(píng)論 0 2
  • 一、了解Vue.js 1.1.1 Vue.js是什么焙畔? 簡(jiǎn)單小巧掸读、漸進(jìn)式、功能強(qiáng)大的技術(shù)棧 1.1.2 為什么學(xué)習(xí)...
    蔡華鵬閱讀 3,323評(píng)論 0 3
  • Vue官方文檔以下內(nèi)容作為本人日常學(xué)習(xí)使用,不作為參考 一儿惫、Vue環(huán)境搭建以及vue-cli的使用 Vue多頁(yè)面應(yīng)...
    好一只帥鹵蛋閱讀 746評(píng)論 0 1