vue源码解析之mustache模板引擎

14 篇文章 0 订阅

数据变为视图的方法

  1. 纯Dom方法:非常笨拙,没有实战价值
  2. 数据join法:曾今流行
  3. ES6反引号法:`${}`语法糖
  4. 模板引擎:解决数据变为视图最优雅的方法

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
}

 

 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值