数据变为视图的方法
- 纯Dom方法:非常笨拙,没有实战价值
- 数据join法:曾今流行
- ES6反引号法:`${}`语法糖
- 模板引擎:解决数据变为视图最优雅的方法
Mustache基础用法
<script id="template" type="x-tmpl-mustache">
<div>hello {{thing}}</div>
</script>
<script type="text/javascript">
var template = $("#template").html();
var r = Mustache.render(template,{
thing:'world'
})
</script>
Mustache原理
什么是token,通过源码发现,token格式如下
模板字符串:
<h1>我买了一个{{thing}},好{{mood}}啊</h1>
对应的tokens:
[
['text','<h1>我买了一个'],
['name','thing'],
['text',',好'],
['name','mood'],
['text','啊</h1>']
]
mustache实现原理
1.index.js入口文件
import parseTemplateToTokens from './parseTemplateToTokens'
import renderTemplate from './renderTemplate'
let mustache = {
render(templateStr,data){
let tokens = parseTemplateToTokens(templateStr)
var dom = renderTemplate(tokens,data)
return dom
}
}
export default mustache
2.parseTemplateToTokens.js解析html字符串为tokens
import Scanner from './Scanner'
import nestTokens from './nestTokens'
export default function parseTemplateToTokens(templateStr){
let scanner = new Scanner(templateStr)
let words
let tokens = []
while (!scanner.eos()) {
words = scanner.scanUtil('{{')
words&&tokens.push(['text',words])
scanner.scan('{{')
words = scanner.scanUtil('}}')
if(words){
switch (words[0]) {
case '#':
tokens.push(['#',words.substring(1)])
break;
case '/':
tokens.push(['/',words.substring(1)])
break;
default:
tokens.push(['name',words])
break;
}
}
scanner.scan('}}')
}
return nestTokens(tokens)
}
3.Scanner .js对html字符串进行扫描
export default class Scanner {
constructor(templateStr) {
this.tail = this.templateStr = templateStr
this.pos = 0
}
//过掉指定标签
scan(tag){
if(this.tail.indexOf(tag)===0){
this.pos +=tag.length
this.tail = this.templateStr.substring(this.pos)
}
}
//查找到某个指定标签
scanUtil(stopTag){
let startPos = this.pos
while (!this.eos()&&this.tail.indexOf(stopTag)!==0) {
this.pos++
this.tail = this.templateStr.substring(this.pos)
}
return this.templateStr.substring(startPos,this.pos)
}
//end of string
eos(){
return this.pos>=this.templateStr.length
}
}
4.nestTokens.js对tokens进行折叠,利用栈的思想以及引用类型的算法
export default function nestTokens(tokens){
let sections = []
let nestTokens=[]
let collector = nestTokens
for(let i = 0;i<tokens.length; i++){
let token = tokens[i]
if(token[0]==='#'){
//进栈
sections.push(token)
collector.push(token)
collector = token[2] = []
}else if(token[0]==='/'){
//出栈
sections.pop()
collector = sections.length?sections[sections.length-1][2]:nestTokens
}else{
collector.push(token)
}
}
return nestTokens
}
5.renderTemplate.js结合数据渲染html字符串
import lookup from './lookup'
export default function renderTemplate(tokens,data){
console.log(tokens,data)
let templateStr = ''
for(var i = 0;i<tokens.length;i++){
let token = tokens[i]
if(token[0]==='text'){
templateStr+=token[1]
}else if(token[0]==='name'){
templateStr+=lookup(token[1],data)
}else if(token[0]==='#'){
//数据递归遍历
var ary = lookup(token[1],data)
for(var j = 0 ;j<ary.length;j++){
templateStr+=renderTemplate(token[2],ary[j])
}
}
}
return templateStr
}
6.lookup.js查找数据
export default function lookup(keyNames,dataObj){
let value = dataObj
//例如a.b.c这种数据查找方法
if(keyNames!=='.'){
var keys = keyNames.split('.')
for(let i = 0;i<keys.length;i++){
var key = keys[i]
value = value[key]
}
}
return value
}