@
目录一、模板引擎的基础概念
1. 模板引擎
模板引擎是第三方模块。
让开发者以更加友好的方式拼接字符串,使项目代码更加清晰、更加易于维护。比如:
// 未使用模板引擎的写法
var ary = [{ name: '张三', age: 20 }];
var str = '<ul>';
for (var i = 0; i < ary.length; i++) {
str += '<li>\
<span>'+ ary[i].name +'</span>\
<span>'+ ary[i].age +'</span>\
</li>';
}
str += '</ul>';
<!-- 使用模板引擎的写法 -->
<ul>
{{each ary}}
<li>{{$value.name}}</li>
<li>{{$value.age}}</li>
{{/each}}
</ul>
2. art-template模板引擎
二、在NodeJS中使用art-template
① 基本使用步骤:
- 在命令行工具中使用
npm install art-template
命令进行下载 - 使用
const template = require('art-template')
引入模板引擎 - 告诉模板引擎要拼接的数据和模板在哪
const html = template(‘模板路径’, 数据);
- 使用模板语法告诉模板引擎,模板与数据应该如何进行拼接
vscode中默认不会把art文件视为html文件,这需要另外设置:参考博客
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
{{ name }}
{{ age }}
</body>
</html>
//引入art-template模板,实际返回一个方法
const template = require('art-template');
const path = require('path');
const views = path.join(__dirname, 'views', '01.art');
/*
template(参数1, 参数2)
参数1: art模板文件路径(优先使用绝对路径)
参数2:art模板文件使用的数据, 对象类型
返回art模板文件字符串(html)
*/
const html = template(views, {
name: '张三',
age: 20,
})
console.log(html);
运行结果:
PS D:\...\template> node app.js
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
张三 20
</body>
</html>
②模板引擎的语法
art-template同时支持两种模板语法:标准语法
和原始语法
。
标准语法可以让模板更容易读写,原始语法具有强大的逻辑处理能力。
1. 输出
将某项数据输出在模板中,标准语法和原始语法如下:
- 标准语法:
{{ 数据 }}
- 原始语法:
<%= 数据 %>
在 输出 语法中,可以进行 变量 的输出、 对象属性 的输出、 三元表达式 输出、 逻辑或 输出、加减乘除等表达式 输出。
<!-- 标准语法 -->
<h2>{{value}}</h2>
<h2>{{a ? b : c}}</h2>
<h2>{{a + b}}</h2>
<!-- 原始语法 -->
<h2><%= value %></h2>
<h2><%= a ? b : c %></h2>
<h2><%= a + b %></h2>
2. 原文输出
如果要输出的 value 值中,包含了 HTML 标签结构,则需要使用原文输出语法,才能保证 HTML 标签被正常渲染。
默认模板引擎不会解析标签,会将其转义后输出。
标准原文输出语法:{{@ 数据 }}
原始原文输出语法:<%- 数据 %>
<!-- 标准语法 -->
<h2>{{@ value }}</h2>
<!-- 原始语法 -->
<h2><%- value %></h2>
3. 条件判断
<!-- 标准语法 -->
{{if 条件}} ... {{/if}}
{{if 条件1}} ... {{else if 条件2}} ... {{/if}}
<!-- 原始语法 -->
<% if (条件1) { %>
...
<% } else if (条件2) { %>
...
<% } else { %>
...
<% } %>
注意:原始语法输出符内部支持原生js语法
4. 循环
标准语法:{{each 数据}} ... {{/each}}
原始语法:<% for() { %> ... <% } %>
<!-- 标准语法
each: 模板循环标识符
target: 要循环的数据
$index: 当前循环项的索引
$value: 当前循环项的值
-->
{{each target}}
{{$index}} {{$value}}
{{/each}}
<!-- 原始语法
原生js语法
-->
<% for(var i = 0; i < target.length; i++){ %>
<%= i %> <%= target[i] %>
<% } %>
5. 子模版
使用子模板可以将网站公共区块(比如头部、底部标签块)抽离到单独的文件中。
通过使用include
将子模板(公共模板) 引入到其他模板中
- 标准语法:
{{include '子模板相对路径'}}
,其中的include表示一个标识符 - 原始语法:
<%include('子模版相对路径模板') %>
,其中的include表示一个方法
<!-- 标准语法 -->
{{include './header.art'}}
<!-- 原始语法 -->
<% include('./header.art') %>
include 引入子模版地址问题
{{include './common/header.art'}}
模板文件中引入公共部分语法中的地址为相对路径,这个相对路径由模板引擎解析,是相对于当前模板文件的路径,而不是相对于当前请求地址路径
6. 模板继承
模板继承指的是其他模板可以继承一些公共模板,类似子模版,但使用模板继承可以将网站HTML骨架抽离到单独的文件中,其他页面模板可以继承骨架文件。
语法:
在其他模板中,使用{{extends '被继承模板的相对路径'}}
去继承公共模板
模板继承可以根据当前模板的需要去指定被继承模板的一些部分
- 在被继承模板中,使用
{{block '预留空名'}}{{/block}}
去设置预留空 - 在其他模板中,使用
{{block '预留空名'}} 指定内容... {{/block}}
去填充预留孔
简单案例:
<!-- 公共骨架模板layout.art -->
<!doctype html>
<html>
<head>
<meta charset="utf-8">
{{block 'title'}}{{/block}}
{{block 'link'}}{{/block}}
</head>
<body>
{{block 'content'}}{{/block}}
</body>
</html>
<!--index.art 首页模板-->
{{extend './layout.art'}}
{{block 'title'}} <title>这是首页</title> {{/block}}
{{block 'link'}} <link rel="stylesheet" href="custom.css"> {{/block}}
{{block 'content'}} <p>This is just an awesome page.</p> {{/block}}
命令行输出
PS D:\...\template> node 05.js
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>这是首页</title>
<link rel="stylesheet" href="custom.css">
</head>
<body>
<p>This is just an awesome page.</p>
</body>
</html>
PS D:\...\test\template>
7. 模板配置
向模板中导入变量
/*
template: 当前js文件导入的 art-template 模板引擎模块
*/
template.defaults.imports.变量名 = 变量值;
语句执行过后便可在所链接的模板中使用该变量
dateformat
使用场景: 在模板中格式化日期数据
引用第三方模块:dateformat - npm
{{dateformat(time, 'yyyy-mm-dd')}}
const template = require('art-template');
const path = require('path');
const dateformat = require('dateformat');
const view = path.join(__dirname, 'views', '06.art');
//! 导入模板变量
template.defaults.imports.dateformat = dateformat;
const html = template(view , {
time: new Date(),
});
console.log(html);
命令行输出
PS D:\...\template> node 06.js
2021-09-01
设置模板根目录
通过多个template()
渲染多个模板,但每次都得手动设置模板地址
const view1 = path.join(__dirname, 'view', '01.art');
const view2 = path.join(__dirname, 'view', '02.art');
console.log(template(view1,{}));
console.log(template(view2,{}));
这样会造成代码冗余..
通过设置模板根目录,让每次调用template()
渲染模板时只需要指定模板文件名,让模板引擎自动到模板根目录下寻找指定的模板文件
/*设置模板的根目录
template: 当前js文件导入的 art-template 模板引擎模块
*/
template.defaults.root = path.join(__dirname, 根目录名);
简单案例
const template = require('art-template');
// 设置模板的根目录
template.defaults.root = path.join(__dirname, 'views');
console.log(template('06.art', {
msg: '06.art模板文件自动被找到并渲染'
}))
设置模板默认后缀
通过设置模板默认后缀名:
// 配置模板的默认后缀
//template: 当前js文件导入的 art-template 模板引擎模块
template.defaults.extname = '.html';
在template()
渲染模板时直接指定模板文件名(不需要后缀):
console.log(template('07', {
msg: '模板引擎自动到模板根目录下寻找 "07.html" 模板文件并渲染'
}));
当然,如果指定了模板文件全名(包含后缀名),模板引擎也会自动到根目录寻找指定文件并渲染。
③ 模板文件外链资源请求地址问题
模板文件中的外链资源路径并不是相对于当前这个模板文件的路径,
而是的相对路径是相对于地址栏中的请求路径的。
比如
地址栏输入localhost/admin/login
,服务器响应一个模板文件并通过引擎解析给浏览器
浏览器是如下解析路径的,它回去找 /admin
这个目录 下的 login
这个文件所以,最后部分其实是指定的文件而不是目录
login.art
模板文件下的外链资源路径是相对于当前模板的请求路径/admin
,比如
<link rel="stylesheet" href="css/base.css">
这个link标签实际发出的请求地址是:localhost/admin/css/base.css
假如此时我们把访问login.art
的请求路径改变localhost/abc/login
,这样模板文件正常访问,但是里面的外链资源依然是相对于/abc
这个路径,然而此时的静态资源是存放在/admin
下的,这时外链资源就会响应失败。
解决方法:把模板文件中的外链资源请求地址 通过'/'
改成 绝对路径
,那么外链资源的请求地址就与当前浏览器的请求地址没关系了,如下
<link rel="stylesheet" href="/admin/css/base.css">
此时外链资源实际的请求地址是localhost/admin/css/base.css
三、在浏览器中使用art-template
① 基本使用步骤
- 下载 art-template-web.js 模板引擎库文件并在 HTML 页面中引入库文件
<!-- 注意: 这里的路径要写绝对路径,不然会相对与url地址的路径, 如果url地址跟当html文件的地址不匹配就会报错 --> <script src="/js/template-web.js"></script>
- 准备 art-template 模板
在模板中支持基本模板语法,与在nodeJS中的模板基本语法一样。<!-- id: id名,用来区分不同不同的模板 type: 在<script>中需要指定html类型 --> <script id="tpl" type="text/html"> <div class="box"></div> </script>
- 告诉模板引擎将哪一个模板和哪个数据进行拼接
/* template: 模板库文件提供的方法 parms1: 模板id名 parms2: 传入模板的数据 return: 根据模板,返回一串特定字符 */ var html = template('tpl', {username: 'zhangsan', age: '20'});
- 通过模板语法告诉模板引擎,数据和html字符串要如何拼接
<script id="tpl" type="text/html"> <div class="box"> {{ username }} </div> </script>
- 将拼接好的html字符串添加到页面中
document.getElementById('container').innerHTML = html;
② 过滤器
- 简介
过滤器是个函数,用来处理特殊值并返回想要的结果
-
语法
{{value | filterName}}
过滤器语法类似 管道操作符,它的上一个输出作为下一个输入。
定义过滤器的基本语法如下:template.defaults.imports.filterName = function(value){/*return处理的结果*/}
- 举例
定义一个 格式化时间 的过滤器dateFormat
如下:
在模板中使用过滤器函数template.defaults.imports.dateFormat = function(date) { var y = date.getFullYear() var m = date.getMonth() + 1 var d = date.getDate() return y + '-' + m + '-' + d // 注意,过滤器最后一定要 return 一个值 } var html = template('tpl',{regTime: new Date()}); console.log(html); /* <div>2021-10-2</div> */
<script type="text/html" id="tpl"> <!--等效 <div>{{dateFormar(regTime)}}</div> --> <div>注册时间:{{regTime | dateFormat}}</div> <script>
② 实现自定义简易的模板引擎
说明
利用正则对字符串的操作,实现自定义模板函数
实现步骤
① 定义模板结构
<!-- 定义模板结构 -->
<script type="text/html" id="tpl-user">
<div>姓名:{{ name }}</div>
<div>年龄:{{ age }}</div>
<div>性别:{{ gender }}</div>
<div>住址:{{ address }}</div>
</script>
② 预调用模板引擎
//定义数据
var data = {name: '张三', age: 20, gender: '男', address: '深圳'}
//调用自定义模板函数
var htmlStr = template('tpl-user', data)
//渲染html解构
document.getElementById("user-box").innerHTML = htmlStr
③ 封装 template 函数
//自定义模板函数 template.js
function template(id, data){
var str = document.getElementById(id).innerHTML
var pattern = /{{\s*([a-zA-Z]+)\s*}}/
var patternResult = null
while(patternResult = pattern.exec(str)){
str = str.replace(patternResult[0], patternResult[1]);
}
return str;
}
④ 导入并使用自定义的模板引擎
如果自定义模板函数在其他文件中,也要导入即可
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>自定义模板引擎</title>
<!-- 导入自定义的模板引擎 -->
<script src="./js/template.js"></script>
</head>