es6實現簡單模板編譯


現在有各種框架,其中一個主要模塊就是關於template。最火的vue、react等框架,在這一塊上也是是下足了功夫。我也想寫一個自己的模板編譯工具,所以就做了個簡單的實現,主要是使用es6的反引號編譯。

1.選擇

這里使用es6的反引號去編譯文本節點,只要把數據放在scope中,我們就可以使用反引號加“${}”的方式去把變量替換掉模板中的內容。

2.編譯內容

首先,我嘗試去直接編譯一個文本,讓變量能夠被填充,模板這么寫

<div id="app">
     <p>your name is ${name}</p>
     <p>your age is ${age}</p>
</div>

模板中${}中的內容是要被替換的。首先我們獲取文本字符串

const root = document.querySelector('#app');
let htmlFragment = root.innerHTML;

然后我們要找出需要替換的變量名,這里用正則查找

const templateReg = /\${([^{}])+}/g;
let res = null;
let keyArray = [];
//把找到的變量存起來
while(res = reg.exec(htmlFragment)){
     let key = res[0].slice(2,res[0].length-1);
     keyArray.push(key);
}

我們在js中定義的數據格式是這樣的

let data = {
     name:"javascript",
     age:"22"
}

接下來,我們把js中的數據格式替換掉模板中的

 for(let item of keyArray){
     let nReg = new RegExp("\\${"+item+"}","g");           
     htmlFragment = htmlFragment.replace(nReg, '${data["'+item+'"]}');
}   

這里說一下為什么要替換,首先是es6中編譯字符串中的變量,這個變量必須在scope中,然后,我們的數據不可能是就像一個一個的變量,那樣要定義太多,還有就是模板中盡量寫法簡潔。所以這里把簡潔的變量替換為正真的scope中的變量。因為是要動態替換,所以正則表達式每次都要重新定義(注意轉義)。
最后就是如何編譯的問題,因為我們拿到的是個字符串,而es6是要用反引號來編譯,所以這里就需要拼接反引號和字符串進行編譯,大家最容易想到的就是eval,但是介於它可能會帶來一些不可預知的東西,所以我們使用new Function()的方式。

let str = new Function("return `"+htmlFragment+"`");
root.innerHTML = "";
//這個方法很久之前就有了,並不是最新出的
root.insertAdjacentHTML('afterbegin',str);

3.編譯模板

這里借鑒vue的節點編譯方式,主要就是對元素節點和文本節點的處理。由於並沒有做循環渲染,所以目前只做了對文本節點的處理。基本的思想還是以一顆樹的形式去一層一層的編譯。

    class Compile{   constructor(node){      this.compileNode(node);      node.hasChildNodes() ? this.compileNodeList(node.childNodes) : null;   }   compileNodeList(nodeList){      let childListFn, node;      for(node of nodeList){         this.compileNode(node);         node.hasChildNodes ? this.compileNodeList(node.childNodes) : null;      }   }   compileNode(node){      console.log(node);      if(node.nodeType == 1){         this.compileElement(node);      }else if(node.nodeType == 3){         this.compileText(node);      }   }   compileElement(node){      //解析指令   }   compileText(node){      //解析模板      node.data;      node.data = this.compileTemplate(node.data)();   }   compileTemplate(textFragment){      let res = null;      let keyArray = [];      while(res = templateReg.exec(textFragment)){         let key = res[0].slice(2,res[0].length-1);         keyArray.push(key);      }      for(let item of keyArray){         let nReg = new RegExp("\\${"+item+"}","g");         console.log(nReg.test(textFragment));         textFragment = textFragment.replace(nReg, '${data["'+item+'"]}');      }      return new Function("return `"+textFragment+"`");   }}//new這個對象即可new Compile(root);

全部的可以去github上看,這個后續也會加強功能。https://github.com/Stevenzwzhai/plugs/tree/master/es6-template


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM