模板引擎原理及部分实现

模板引擎,是前端MV*架构中view的重要组成部分,是为了使用户界面与业务数据(内容)分离而产生的,它可以生成特定格式的文档,用于网站的模板引擎就会生成一个标准的HTML文档。多数前端框架都用到了前端模板引擎。

前端模板引擎类型

前端模板引擎主要分三类:

  • string-based模板,基于字符串的parse和compile,如ejs、hbs;
  • dom-based模板,基于dom的link或compile,如angular、vue的模板;
  • 虚拟dom模板,基于v-dom和ast,如React的模板jsx。

字符串模板引擎

1.String-based模板原理

字符串模板引擎主要依赖一下这几个dom API:createElement,appendChild,innerHTML
在这些api中,innerHTML有最佳的可读性与实用性,成为事实上的主要标准,虽然其他API可能在性能上更胜一筹,但原生js的字符串生成方案中,最常用的还是innerHTML
构建过程如下:

1.把整个文档作为字符串输入。
2.通过一个带正则的函数,将模板按照标记分为js表达式、模板语法、正常HTML语法。
3.合并成一个js表达式,这个可以接受数据作为输入。
4.输入数据后,输出字符串。
5.该字符串即可拼接为html代码。

2.String-based模板实现demo

大概实现下,约定一个语法,以经典的双大括号{{}}作为模板插值。模板如下:

<div id="app"></div>
<script type="text/tpl" id="template">
    <p>name: {{name}}</p>
    <p>age: {{age}}</p>
</script>

插入的数据:

var info = [
    {
        name: 'bugzhang',
        age: 22
    }, {
        name: 'justzht',
        age: 20
    }, {
        name: 'zp',
        age: 20
    }
];

最重要的模板解析:

//解析模板
function template(tpl, data) {
    //定义解析模式
    var re = /{{(.+?)}}/g,
        cursor = 0
    reExp = /(^( )?(var|if|for|else|switch|case|break|{|}|;))(.*)?/g,
        code = 'var r=[];\n';

    // 解析html
    function parsehtml(line) {
        // 单双引号转义,换行符替换为空格,去掉前后的空格
        line = line.replace(/('|")/g, '\\$1').replace(/\n/g, ' ').replace(/(^\s+)|(\s+$)/g, "");
        code += 'r.push("' + line + '");\n';
    }

// 解析js代码       
    function parsejs(line) {
        // 去掉前后的空格
        line = line.replace(/(^\s+)|(\s+$)/g, "");
        code += line.match(reExp) ? line + '\n' : 'r.push(' + line + ');\n';
    }

    while ((match = re.exec(tpl)) !== null) {
        // 开始标签  {{ 前的内容和结束标签 }} 后的内容
        parsehtml(tpl.slice(cursor, match.index))
        // 开始标签  {{ 和 结束标签 }} 之间的内容
        parsejs(match[1])
        // 每一次匹配完成移动指针
        cursor = match.index + match[0].length;
    }
    // 最后一次匹配完的内容
    parsehtml(tpl.substr(cursor, tpl.length - cursor));
    code += 'return r.join("");';
    return new Function(code.replace(/[\r\t\n]/g, '')).apply(data);
}
//把生成的字符串插入app节点
var tpl = document.getElementById("app").innerHTML.toString();
document.getElementById("content").innerHTML = template(tpl, info);
3.String-based模板优点与缺点

优点主要有:

  • 快速的初始化时间
  • 同时适用于服务器端与客户端,对SSR有最好的支持度
  • 语法支持好

缺点也很明显:

  • 存在安全隐患
  • 性能较低下
  • 渲染后与数据断开联系

dom模板引擎

1.原理概述

dom-based模板引擎,输出的直接是dom,很多著名框架的模板都是采用了dom-based模板,如angular.js,vue.js,avalon.js,regular.js。
构建过程如下:

1.从字符串中生成不带数据的无状态模板;
2.从无状态模板编译成动态模板;
3.动态模板与model进行绑定,完成插值的功能。

2.优缺点

优点主要有:

  • 与数据绑定,可以不需要操作dom更改view
  • 运行高效
  • 指令带来的声明式开发

缺点:

  • 安全问题
  • 信息冗余度高
  • 初次进入dom的内容不是最终想要的内容

V-dom模板

目前了解不多,而且v-dom内容比较多,以后再单独写这块。

参考:https://segmentfault.com/a/1190000004420078,http://blog.csdn.net/yczz/article/details/49585381

发表评论

电子邮件地址不会被公开。 必填项已用*标注

😉😐😡😈🙂😯🙁🙄😛😳😮:mrgreen:😆💡😀👿😥😎😕