继续浏览精彩内容
慕课网APP
程序员的梦工厂
打开
继续
感谢您的支持,我会继续努力的
赞赏金额会直接到老师账户
将二维码发送给自己后长按识别
微信支付
支付宝支付

前端模版引擎 - artTemplate 【上】

PIPIONE
关注TA
已关注
手记 1063
粉丝 147
获赞 702

前言

因为工作的关系,我在接手项目的时候发现以前的同事都是用 artTemplate 进行模板渲染的。鉴于它方便用于 Ajax 请求数据并渲染的操作并在项目应用颇多,所以在我开发新的项目时,也把其作为一个主要的 library 插件,同时利用 gulp 进行 artTemplate 的预编译。下面就是我在新项目的使用过程中遇到的问题总结出来的经验以及 artTemplate 的使用方法,以供参考。

1. artTemplate介绍

一个渲染性能出众模板引擎,无论在 NodeJS 还是在浏览器中都可以运行。

webp

渲染模板速度对比



特性
  • 拥有接近 JavaScript 渲染极限的的性能

  • 调试友好:语法、运行时错误日志精确到模板所在行;支持在模板文件上打断点(Webpack Loader)

  • 支持压缩输出页面中的 HTML、CSS、JS 代码

  • 支持 Express、Koa、Webpack

  • 支持模板继承与子模板

  • 兼容 EJSUnderscoreLoDash 模板语法

  • 模板编译后的代码支持在严格模式下运行

  • 支持 JavaScript 语句与模板语法混合书写

  • 支持自定义模板的语法解析规则

  • 浏览器版本仅 6KB 大小

简单来说就是把以前你通过字符串拼接,再用 js append 到 dom 然后再填充数据的方式转变为另外一种便于阅读,代码优雅,性能更快的模板引擎。


2. artTemplate版本问题

因为在工作中遇到一些问题,在上网查文档的时候发现怎么 artTemplate 会有两个:

  1. artTemplate
    你在百度搜索时,第一个应该是 jQuery 插件库网站上介绍的 artTemplate-3.0 (这个也是本司原项目使用的版本),但是你会发现怎么很多链接都报 404 根本没使用。只好上 GitHub 上搜索,第一条的是 lhywork/artTemplate 链接还是 404 ,而且 Stars 数量这么少让我一度怀疑这个项目是不是报废了,因为我看到网上说作者停止维护该项目的信息。

  2. art-template
    在漫无目的的搜索后,我又发现一个叫 art-template 的库,上面的写法跟 artTemplate 差不多,但我在用辅助方法时却发现,原项目中的过滤器:
    template.helper(name, callback)
    不能用了,现在变成了
    template.defaults.imports.dateFormat = function(date, format){/*[code..]*/};
    一度以为这是两个不同的项目,导致我只能通过别人的博客寻找解决项目问题的方法。

直到我空下来说研究一下这个 art-template 并想找到 artTemplate 的作者询问些问题(因为在 gulp 预编译 artTemplate 的过程中出现了一个大坑),才发现原来两个作者都是同一个人,这位叫 糖饼 的大哥,一位爱改名字且爱删东西的大哥。

webp

说好的后会无期呢?

在短短几个月后他又发现 artTemplate 并没有被市面上的 dom模板所彻底打败,它依然有所作为,所以他又开发了一个新的版本并改名为 art-template。同时 Branch 下的 3.1.0 README.md 文档中的链接已经失效了( 他删掉了 ),这极大的不方便接手别人项目的同学学习。不过可以在 distdemo 再次取得部分的资料。

下面我将对这两个版本一些要点进行说明与记录,并且只进行简洁语法说明,方便以后大家使用。


3. artTemplate - 3.0

这个版本应该是目前应用最多的,其有以下五种使用方法,

a. 浏览器版本

直接引入 template.js 文件,下面示例代码中将包含:

  • 基础使用 - script 标签用法

  • 不转义 html 方法

  • 打印 - {{print}}

  • 过滤器 - template.help

  • debug

  • 模板外置

  • 模板嵌套 - 子模板(include)

demo-index.html - 基本 API 用法

<!DOCTYPE HTML><html><head><meta charset="UTF-8"><title>浏览器版本-demo</title><script src="template.js"></script>  //引入 template.js</head><body><div id="content"></div><script id="test" type="text/html">  //模板编写在 <script> 标签中,添加 id 与 type 

{{if isAdmin}}   //条件判断写法<h1>{{title}}</h1>   //双花括号取值<ul>    /**
    循环数组数据渲染写法,等价于:
    for(var i in list){ 
       list[i] == value; // true
    }
   */

    {{each list as value i}}     
        <li>索引 {{i + 1}} :{{value}}</li>
    {{/each}}</ul>{{#value}}   //因为保护措施 artTemplate 会转义 HTML 代码为字符串输出,当你不需要转换时只需要前面加个 # 号{{print title value}}  // print 用法 - 会输出 “基本例子<span style="color:#F00">hello world!</span>”{{time | format}}   //格式化过滤器方法 {{data | 过滤器名字}}{{format(time)}}   //敢信还能这么写{{# format(time)}} //所以不转义可以和过滤器这样结合这个是不存在的空数据:{{undefined}}   //在 data 中不存在的数据 artTemplate 将会置空处理这个会报错,去除注释后自行检验://{{undefined.child}}  //但如果是数据绑定用的是点对象的方法,将会报错在 dom 中显示 {Template Error} 并在控制台中输出 bug ( ps. 想要捕获 bug 只能通过修改 artTemplate 源码的方法,因为它并有暴露 debug 接口 ){{/if}}</script><script>//数据必须是一个对象var data = {    title: '基本例子',    isAdmin: true,    list: ['文艺', '博客', '摄影', '电影', '民谣', '旅行', '吉他'],    value: '<span style="color:#F00">hello world!</span>'};//过滤器注册template.helper('format', function (date, format) {  // 对传入的data进行处理再 return 出去
  return format;
});//渲染var html = template('test', data);document.getElementById('content').innerHTML = html;</script></body></html>

compile.js - 模板外置方法

/**
大量页面希望引入同一个模板时,不可能每个页面都添加相同的 <script>
 所以需要从外部定义一个公共的 js 文件,让各个页面公用一个模板
*/
var source = '<ul>'
+    '{{each list as value i}}'
+        '<li>索引 {{i + 1}} :{{value}}</li>'
+    '{{/each}}'
+ '</ul>';

//但页面中引入公共 js 后,通过下面方法获取并渲染
var render = template.compile(source);
var html = render({
    list: ['摄影', '电影', '民谣', '旅行', '吉他']
});
document.getElementById('content').innerHTML = html;

//这样做的缺点很明显,需要通过字符串拼接的方式,不仅麻烦且不美观

———————————————————————————————————

//这里我再提供另一个方法,可以引用 html 文件作为模板,在页面中引入< link rel = "import" href = "module.html" id = "tests">模板则是一个 html 文件,module 用 <script> 包裹起来<script type="text/html" id="demo">
    <div>
        引入    </div></script>//然后我们再通过<script type="text/javascript">
        var module = document.querySelector('#tests').import.querySelector('script');        document.querySelector('head').appendChild(module);        var data = {};        var html = template('demo', data);        document.getElementById('content').innerHTML = html;</script>// rel = "import" 可能存在兼容问题,低版本的浏览器慎用。

include.html - 模板嵌套代码

<body>
    <div id="content"></div>
    <script id="test" type="text/html">
        <h1>{{title}}</h1> 
        {{include 'list'}}  // 默认使用当前数据        {{include 'list' list}}  // 可以指定数据    </script>
    <script id="list" type="text/html">
        <ul>
            {{each list as value i}}
            <li>索引 {{i + 1}} :{{value}}</li>
            {{/each}}
        </ul>
    </script>

    <script>
        var data = {            title: '嵌入子模板',            list: ['文艺', '博客', '摄影', '电影', '民谣', '旅行', '吉他']
        };        var html = template('test', data);        document.getElementById('content').innerHTML = html;    </script></body>
b. NodeJS 应用

当你想在 Node 环境下运用 artTemplate 时,可以采用下面的方法:

安装

$ cnpm install art-template@3.1.3

因为现在 art-template 已经是开发到 4.12.1 了所以想要兼容上一个版本的 artTemplate 需要下载对应版本的 npm 插件。

ps. 想查看某个插件含有多少的版本可以敲以下命令

$ cnpm view art-template versions

使用

var template = require('art-template');var data = {list: ["aui", "test"]};var html = template(__dirname + '/index/main', data);

ps. 更多配置与详情自行查看 GitHub 说明

接下来就是预编译模式,其意思是默认将整个目录的模板(html文件)压缩打包到一个名为 template.js 的脚本中,并无需引用浏览器版本的 template.js ,可直接在页面中使用它:

<script src="tpl/build/template.js"></script><script>
    var html = template('news/list', data);  // 这里的模板 ID 就是你存放模板的路径
    document.getElementById('list').innerHTML = html;</script>
c. node工具 -  tmodjs

安装

$ cnpm install -g tmodjs

编译

tmod [模板目录] [配置参数] [模板输出目录]
示例:$ tmod ./tpl --output ./build

配置参数

插件介绍
--debug输出调试版本
--charset value定义模板编码,默认utf-8
--output value定义输出目录,默认./build
--type value定义输出模块格式,默认default,可选cmd、amd、commonjs
--no-watch关闭模板目录监控
--version显示版本号
--help显示帮助信息

插件配置

插件的配置则是写在 package.json 文件中:

{    "name": "template",    "version": "1.0.0",    "dependencies": {        "tmodjs": "1.0.0"
    },    "tmodjs-config": {        "output": "./build",        "charset": "utf-8",        "syntax": "simple",        "helpers": null,        "escape": true,        "compress": true,        "type": "default",        "runtime": "template.js",        "combo": true,        "minify": true,        "cache": false
    }
}
字段类型默认值说明
outputString"./build"编译输出目录设置。如果设置为 false 则不输出
charsetString"utf-8"模板使用的编码(暂时只支持 utf-8)
syntaxString"simple"定义模板采用哪种语法。可选:simple、native
helpersStringnull自定义辅助方法路径
escapeBooleantrue是否过滤 XSS。如果后台给出的数据已经进行了 XSS 过滤,就可以关闭模板的过滤以提升模板渲染效率
compressBooleantrue是否压缩 HTML 多余空白字符
typeString"default"输出的模块类型,可选:default、cmd、amd、commonjs
runtimeString"template.js"设置输出的运行时名称
aliasStringnull设置模块依赖的运行时路径(仅针对于非default的类型模块配置字段。如果不指定模块内部会自动使用相对 runtime 的路径)
comboBooleantrue是否合并模板(仅针对于 default 类型的模块)
minifyBooleantrue是否输出为压缩的格式
cacheBooleantrue是否开启编译缓存
verboseBooleantrue是否打印日志
d. Grunt插件 -  grunt-tmod

@Jsonzhang 开发

安装

$ cnpm install grunt-tmod --save-dev//加载插件grunt.loadNpmTasks('grunt-tmod');

使用

module.exports = function(grunt){

    grunt.initConfig({        tmod: {            template: {                src: './tpl/**/*.html',                dest: './dist/template.js',                options: {                    combo: true,                    base: './tpl/src'  // 这个什么意思看下面的 Gulp 说明,很重要
                } 
            }
        }
    });


    grunt.loadNpmTasks('grunt-tmod');

    grunt.registerTask('default', ['tmod']);

};//更多查看 GitHub 项目地址
e. Gulp插件 -  gulp-tmod

@lichunqiang 开发

安装

$ cnpm install gulp-tmod --save-dev

使用

var tmodjs = require('gulp-tmod');//编译功能代码gulp.task('art', function() {    var stream = gulp.src(src.common.template)
        .pipe(tmod({            templateBase: 'app/src/common/template'
        }))
        .pipe(gulp.dest(dist.common.template));    console.log("artTemplate编译完成!");    return stream;
});

由于本人目前就是采用该方法,所以理解较深,使用过程中有几点的需要注意的问题稍微跟大家提及一下,其他方法也可以参照使用:

  1. templateBase
    这里的 templateBase 是替换掉生成的 template.js 文件中模板ID的,比如我们的模板是 “app/src/common/template/demo.html” ,这时候引用改模板是这样使用的

//默认去掉 .html 后缀var html = template('app/src/common/template/demo', data);document.getElementById('content').innerHTML = html;

当我们设置了 base 值

 .pipe(tmod({            templateBase: 'app/src/common/template'
        }))// 引用时只需要var html = template('demo', data);document.getElementById('content').innerHTML = html;
  1. 监察的写法
    利用 Gulp 的 watch API

//artTemplate
    var watcherArt = gulp.watch('app/src/common/template/**/**.html', ['art']);
    watcherArt.on('change', function(event) {        console.log('该模板 ' + event.path + ' was ' + event.type + ', 执行artTemplate编译...');
    });
  1. 当编译完成后,template.js 却没有任何改变 ( 绝对重点
    这个是很危险的一个坑,它不会在控制台中输出 bug ,而是正常的完成编译。让你一直以为是插件,还是环境什么的问题,这曾经浪费我大量的时间找 bug 。后来有一个报 bug 的文件一闪而过,我到现在都不知道它是在什么情况下才会生成。

不过你只要记住!它编译后没改变文件的原因只有一个,就是你丫的模板 html
的语法写错了!

重新检查一下,再次编译吧!

ps. 模板的 html 文件就是简单的 dom 不需要干别的事情,例:

<section class="module-main">
    <header>
        <span class="title-circle title-circle-blue"></span>{{title}}        <div class="triangle-btn showArticle">
            <span class="mui-icon mui-icon-arrowdown "></span>
        </div>
    </header>
    <div class="article">
        {{data}}    </div></section>

我看这篇幅已经很长了,所以决定分为上下两篇~

下篇《 前端模版引擎 - art-template【下】》



作者:Max_Law
链接:https://www.jianshu.com/p/b5dffff259be


打开App,阅读手记
1人推荐
发表评论
随时随地看视频慕课网APP