本文以ejs为例,简单介绍模板引擎的实现原理。
模板引擎(ejs)的使用示例

先提供一个模板文件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<!-- template.html文件的内容 -->
<!DOCTYPE html>
<html lang="en">
<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>Document</title>
</head>
<body>
<%=author%><%=age%><%=address%>
<%arr.forEach(item=>{%>
<li><%=item%></li>
<%})%>
</body>
</html>

这里给出ejs引擎的使用示例,在执行前需要先执行npm init -ynpm i ejs命令来安装模块。

1
2
3
4
5
6
7
8
const ejs = require("ejs");
const path = require("path");

ejs.renderFile(path.resolve(__dirname, "template.html"),
{author: "文顶顶", age:18, address:"远方", arr:["liuYi", "MiaoXia", "XiaoXia", "Jia"]},
(err, data) => {
console.log(err, data);
})

运行上面的代码来进行渲染,将得到下面的html页面。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
null <!DOCTYPE html>
<html lang="en">

<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>Document</title>
</head>

<body>
文顶顶 18 远方
<li> lY </li>
<li> MiaoXia </li>
<li> XiaoXia </li>
<li> Jia </li>
</body>

</html>

实现原理

模板引擎的实现原理本质上就是利用new Function来执行字符串,利用with特性来框定作用域传递数据,利用正则表达式来实现特定字符的替换工作,再加上冗长的字符串拼接。

给出自己写的readFile文件代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
const fs = require("fs");
const path = require("path");

let renderFile = (filePath, obj, cb) => {
/* 1、先读取文件的内容 */
fs.readFile(filePath, "utf-8", (err, html) => {
if (err) {
cb(err, html);
}

/* 2、拼接字符串 */
let head = "let str = '';\r\n with(obj){";
head += "str +=`";

/* 使用正则处理<%=author%>部分 替换为${author} */
let body = html.replace(/<\%=([^%]+)\%>/g, function() {
return "${" + arguments[1] + "}";
});

/* 继续使用正则处理<%arr.forEach(item=>%>部分 删除标签 */
body = body.replace(/<\%([^%]+)\%>/g, function() {
return "`;\r\n" + arguments[1] + "\r\nstr+=`";
});

let end = "`}";
html = head + body + end + "return str";

/* 3、执行字符串(new Function) */
let fn = new Function('obj', html);

/* 4、执行回调传递渲染后的结果 */
cb(null, fn(obj))
})

}

renderFile(path.resolve(__dirname, "template.html"),
{author: "文顶顶",age:18, address:"远方", arr: ["liuYi", "MiaoXia", "XiaoXia", "Jia"]},
(err, data) => {
console.log(err, data);
})