Vue源码解析——mustache模板引擎 | 青训营笔记

185 阅读1分钟

前言

这是我参与「第四届青训营 」笔记创作活动的第3天

随着挨踢行业的不断内卷化,了解Vue框架的底层原理已刻不容缓。

数据变为视图的方法

问题:如果我们要将下面的arr循环渲染成无序列表,该怎么做呢?

var arr = [
            { "name": "小明", "age": 12, "sex": "男" },
            { "name": "小红", "age": 11, "sex": "女" },
            { "name": "小强", "age": 13, "sex": "男" }
        ];

解决方案

  • 纯DOM:非常笨拙,没有实战价值,最为底层

  • 数组join法:曾几何时非常流行,是曾经前端必会的知识

  • ES6的反引号法:ES6中新增的${a}语法糖,好用

  • 模板引擎:可省略循环语句,解决数据变为视图最优雅的方法

今天就模板引擎着重讲一下------

mustache库

简介

  • mustache官方git: github.com/janl/mustac…
  • mustache是“胡子”的意思,因为它的嵌入标记{{ }}非常像胡子
  • 没错,{{ }}的语法也被Vue沿用,这就是我们学习mustache的原因
  • mustache是最早的模板引擎库,比Vue诞生的早多了,它的底层实现机理在当 时是非常有创造性的、轰动性的,为后续模板引擎的发展提供了崭新的思路

基本使用

了解

  • 必须要引入mustache库,可以在bootcdn.cn上找到它
  • mustache的模板语法非常简单,比如前述案例的模板语法如下:
<ul>
// 循环开始
{{#arr}}
<li>
<div class="hd">{{name}}的基本信息</div>
<div class="bd">
<p>姓名:{{name}}</p>
<p>性别:{{sex}}</p>
<p>年龄:{{age}}</p>
</div>
</li>
{{/arr}}
// 循环结束
</ul>

循环对象数组

  • 引入mustache.js第三方库,就会提供一个Mustache的全局对象
  • Mustache.render(templateStr, data)

注:templateStr 是 要填的模板字符串,data 是要循环渲染的数据。

下面代码执行就可以生成无序列表了!!!

<div id="container"></div>

    <!-- 模板 -->
    <script type="text/template" id="mytemplate">
        <ul>
            {{#arr}}
                <li>
                    <div class="hd">{{name}}的基本信息</div>    
                    <div class="bd">
                        <p>姓名:{{name}}</p>    
                        <p>性别:{{sex}}</p>    
                        <p>年龄:{{age}}</p>    
                    </div>
                </li>
            {{/arr}}
        </ul>
    </script>
    // 引入mustache库
    <script src="jslib/mustache.js"></script>
    <script>
        var templateStr = document.getElementById('mytemplate').innerHTML;

        var data = {
            arr: [
                { "name": "小明", "age": 12, "sex": "男" },
                { "name": "小红", "age": 11, "sex": "女" },
                { "name": "小强", "age": 13, "sex": "男" }
            ]
        };

        var domStr = Mustache.render(templateStr, data);
        var container = document.getElementById('container');
        container.innerHTML = domStr;
    </script>

数组的嵌套

<div id="container"></div>

    <script src="jslib/mustache.js"></script>
    <script>
        var templateStr = `
            <ul>
                {{#arr}}
                    <li>
                        {{name}}的爱好是:
                        <ol>
                            {{#hobbies}} 
                                <li>{{.}}</li>
                            {{/hobbies}} 
                        </ol>
                    </li>    
                {{/arr}}
            </ul>
        `;
        // {{#hobbies}}...{{/hobbies}}表示循环数组arr中的各数组hobbies
        var data = {
        // 数组嵌套
            arr: [
                {'name': '小明', 'age': 12, 'hobbies': ['游泳', '羽毛球']},
                {'name': '小红', 'age': 11, 'hobbies': ['编程', '写作文', '看报纸']},
                {'name': '小强', 'age': 13, 'hobbies': ['打台球']},
            ]
        };

        var domStr = Mustache.render(templateStr, data);
        
        var container = document.getElementById('container');
        container.innerHTML = domStr;
    </script>

正则表达式实现模板数据填充

  • 在较为简单的情况下,可以用正则表达式实现
var templateStr = '<h1>我买了一个{{thing}},花了{{money}}元,好{{mood}}</h1>';

        var data = {
            thing: '白菜',
            money: 5,
            mood: '激动'
        };

        // 最简单的模板引擎的实现机理,利用的是正则表达式中的replace()方法。
        // replace()的第二个参数可以是一个函数,这个函数提供捕获的东西的参数,就是$1
        // 结合data对象,即可进行智能的替换
        function render(templateStr, data) {
            return templateStr.replace(/\{\{(\w+)\}\}/g, function (findStr, $1) {
                return data[$1];
            });
        }

        var result = render(templateStr, data);
        console.log(result);
  • 但是当情况复杂时,正则表达式的思路肯定就不行了。比如这样的模板字符串, 是不能用正则表达式的思路实现的

mustache库的机理

mustache库的机理大致可归纳为:

  1. 将模板字符串编译为tokens形式
  2. 将tokens结合数据,解析为dom字符串

image.png

image.png

底层tokens思想

1.先了解一下什么是tokens:

  • tokens是一个JS的嵌套数组,说白了,就是模板字符串的JS表示
  • 它是“抽象语法树”、“虚拟节点”等等的开山鼻祖

image.png

2.将模板字符串编译为tokens

image.png

3.至于如何将模板字符串编译为tokens,看下行代码

// 引入mustache库
<script src="jslib/mustache.js"></script>
    <script>
        var templateStr2 = `
            <ul>
                {{#arr}}
                    <li>
                        {{name}}的爱好是:
                        <ol>
                            {{#hobbies}} 
                                <li>{{.}}</li>
                            {{/hobbies}} 
                        </ol>
                    </li>    
                {{/arr}}
            </ul>
        `;
        // 将模板字符串编译为`tokens`
        Mustache.render(templateStr2, {});
    </script>

执行上述代码,效果如下:

image.png

总结

学习源码时,源码思想要借鉴,而不要抄袭。记得多敲多想,你会有不一样的收获哦。源码参悟之时,年薪百万之日!