? ? ? ? vue之mustache庫的機理其實是將模板字符串轉化為tokens 然后再將 tokens 轉化為 dom字符串,如下圖
?對于一般的將模板字符串轉化為dom字符串,這樣不能實現復雜的功能
let data = {name:'小王',age:18
}
let templateStr = `<h1>我叫{{name}},我今年{{age}}歲<h1>
`
templateStr = templateStr.trim()let htmlStr = templateStr.replace(/\{{(\w+)}}/g,function(match,$1,index){//第一個參數為他尋找的部分,第二個為捕獲的東西,第三個所在的位置,第四個為該字符串return data[$1] })
console.log(htmlStr) //我叫小王,我今年18歲
?將模板字符串轉化為tokens
前面已經知道了musache的工作原理為 將模板字符串轉化為tokens,然后再將tokens轉化為BOM字符串所以此小節的任務為:
class Scanner {constructor (templateStr ){//將模板字符串寫到實例身上this.templateStr = templateStr//指針this.pos = 0//尾巴,剛開始為字符串本身this.tail = templateStr}//讓指針跳過目標,進而掃描后面的內容scan(target){this.pos += target.lengththis.tail = this.templateStr.substring(this.pos)}//掃描字符串,直到掃描到目標,返回目標之前的字符串scanUtil(target) {let recordPosValue = this.pos//如果該字符串的地一個元素即該目標的索引不為0時,說明指針還需要往右走while(this.tail.indexOf(target)!=0&&this.pos<this.templateStr.length){this.pos++;//尾巴變為pos后面的部分this.tail = this.templateStr.substring(this.pos)}return this.templateStr.substring(recordPosValue,this.pos)}
}
export default function becomeEasyToken (templateStr){let token = []//實例化一個掃描器,針對模板字符串工作let scanner = new Scanner(templateStr)while(scanner.pos<templateStr.length){let word;word = scanner.scanUtil('{{');if(word !=''){token.push(["text",word])}scanner.scan('{{')word = scanner.scanUtil("}}")if(word !=''){if(word[0] == "#"){token.push(["#",word.substring(1)])}else if(word[0]=="/"){token.push(['/',word.substring(1)])}else{token.push(["name",word])}}scanner.scan("}}")}return token
}
以上代碼沒有處理 "#" 的循環功能?,所以還必須添加一個函數,并對該返回值稍加修改
import foldToken from "./foldToken";
export default function becomeEasyToken (templateStr){let token = []//實例化一個掃描器,針對模板字符串工作let scanner = new Scanner(templateStr)while(scanner.pos<templateStr.length){let word;word = scanner.scanUtil('{{');if(word !=''){token.push(["text",word])}scanner.scan('{{')word = scanner.scanUtil("}}")if(word !=''){if(word[0] == "#"){token.push(["#",word.substring(1)])}else if(word[0]=="/"){token.push(['/',word.substring(1)])}else{token.push(["name",word])}}scanner.scan("}}")}return foldToken(token)
}
export default function foldToken(tokens) {//結果數組let nestedTokens = []//棧結構,存放小tokenslet section = [];//與nestedTokens指向的是同一數組,該數組為一級數組let collentor = nestedTokensfor (const item of tokens) {switch (item[0]) {case "#"://進棧section.push(item)collentor.push(item)//創建新一級的數組collentor = item[2] = [] break;case "/"://出棧section.pop(item)//如果都出完了,則回到一級數組,還沒出完則回到其上一級collentor = section.length>0?section[section.length-1][2]:nestedTokensbreak;default://僅負責給各級數組添加 "text" 元素collentor.push(item)}}return nestedTokens;
}
效果展示:
?