node.js之模板引擎artTemplate
什么是模板引擎
模板引擎是第三方模块。让开发者以更加友好的方式拼接字符串,使项目代码更加清晰、更加易于维护。
模板引擎使用步骤:
1,在命令行工具中使用 npm install art-template 命令进行下载
2,使用const template = require('art-template')引入模板引擎
3,告诉模板引擎要拼接的数据和模板在哪 const html = template(‘模板路径’, 数据);
4,使用模板语法告诉模板引擎,模板与数据应该如何进行拼接
1 // 导入模板引擎 2 // 返回的template是一个方法 3 const template = require("art-template"); 4 5 // 导入路径拼接方法 6 const path = require("path"); 7 // 拼接路径 8 const views = path.join(__dirname,"views","index.art"); 9 10 // template 方法是用来拼接字符串的 11 // 参数1:模板的路径 绝对路径。绝对路径最后一个为文件名。文件名的后缀要为.art 12 // 参数2:对象,即要在模板中显示的数据 13 // 返回值:拼接好的字符串 14 const html = template(views,{ 15 name:"张三", 16 age:20 17 }); 18 19 console.log(html); 20 21 22 ------------------------------------------------------------ 23 // 使用模板引擎就要有模板,并且模板的后缀名为 .art 24 // 模板代码:在模板代码可以使用模板引擎中传过来的数据 25 26 <!doctype html> 27 <html lang="en"> 28 <head> 29 <meta charset="UTF-8"> 30 <title>Document</title> 31 </head> 32 <body> 33 34 {{name}} 35 36 {{age}} 37 38 39 </body> 40 </html>
模板语法
模板引擎的语法,主要都是讲的在模板中使用这些语法,可以让template(‘模板路径’, 数据);中的数据在模板中运用。
art-template同时支持两种模板语法:标准语法和原始语法。
标准语法可以让模板更容易读写,原始语法具有强大的逻辑处理能力。
标准语法: {{ 数据 }} 原始语法:<%=数据 %>
输出
输出语法
标准语法:{{ 数据 }}
原始语法:<%=数据 %>
1 <!doctype html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <meta name="viewport" 6 content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"> 7 <meta http-equiv="X-UA-Compatible" content="ie=edge"> 8 <title>Document</title> 9 </head> 10 <body> 11 12 <!-- 标准语法 --> 13 <p>{{ name }}</p> 14 <p>{{1+1}}</p> 15 <p>{{ 1+1 == 2 ? "相等":"不相等"}}</p> 16 17 18 <!-- 原始语法 --> 19 <p><%=name%></p> 20 <p><%=1+1%></p> 21 <p><%=1+1 ==2 ?"相等":"不相等"%></p> 22 23 </body> 24 </html>
1 // 导入模板引擎 2 // 返回的template是一个方法 3 const template = require("art-template"); 4 // 用于拼接路径 5 const path = require("path"); 6 7 const views = path.join(__dirname,"views","01.art"); 8 // template 方法是用来拼接字符串的 9 // 参数1:模板的路径 绝对路径。绝对路径最后一个为文件名。文件名的后缀要为.art 10 // 参数2:对象,即要在模板中显示的数据 11 // 返回值:拼接好的字符串 12 const html = template(views,{ 13 name:"张三", 14 age:20, 15 }); 16 17 console.log(html); 18 19 /* 20 输出结果 21 22 <body> 23 <!-- 标准语法 --> 24 25 <p>张三</p> 26 <p>2</p> 27 <p>相等</p> 28 29 <!-- 原始语法 --> 30 <p>张三</p> 31 <p>2</p> 32 <p>相等</p> 33 </body> 34 */
注意:模板引擎中的数据,可以是template方法中传过来的数据,也可以是算数运算符,还可以是三元运算符。
原文输出
原文输出:如果我们想传递HTML代码,那么模板引擎并不会将HTML代码中的特殊符号进行解码,还是以编码的形式显示。
例如:<h1> 在模板中最后显示为 <h1>
那么我们就需要让这些特殊符号在模板中原文显示。
原文显示的语法:
标准语法:{{@ 数据 }}
原始语法:<% - 数据 %>
1 <!doctype html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <meta name="viewport" 6 content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"> 7 <meta http-equiv="X-UA-Compatible" content="ie=edge"> 8 <title>Document</title> 9 </head> 10 <body> 11 12 <!-- 标准语法 --> 13 <p>{{content}}</p> 14 <p>{{@content}}</p> 15 16 <!-- 原始语法 --> 17 <p><%=content%></p> 18 <p><%-content%></p> 19 20 </body> 21 </html>
1 // 导入模板引擎 2 // 返回的template是一个方法 3 const template = require("art-template"); 4 5 const path = require("path"); 6 7 const views = path.join(__dirname,"views","01.art"); 8 // template 方法是用来拼接字符串的 9 // 参数1:模板的路径 绝对路径。绝对路径最后一个为文件名。文件名的后缀要为.art 10 // 参数2:对象,即要在模板中显示的数据 11 // 返回值:拼接好的字符串 12 const html = template(views,{ 13 content:"<h1>我是标签</h1>" 14 }); 15 16 console.log(html); 17 18 /* 19 输出 20 <body> 21 22 <!-- 标准语法 --> 23 <p><h1>我是标签</h1></p> 24 <p><h1>我是标签</h1></p> 25 26 <!-- 原始语法 --> 27 <p><h1>我是标签</h1></p> 28 <p><h1>我是标签</h1></p> 29 30 </body> 31 */
条件判断
1 <!-- 标准语法 --> 2 {{if 条件}} ... {{/if}} 3 {{if v1}} ... {{else if v2}} ... {{/if}} 4 5 <!-- 原始语法 --> 6 <% if (value) { %> ... <% } %> 7 <% if (v1) { %> ... <% } else if (v2) { %> ... <% } %>
1 // 标准语法 2 {{if age>18}} 3 年龄大于18 4 {{else if age<15}} 5 年龄小于15 6 {{else}} 7 年龄不符合要求 8 {{/if}} 9 10 11 // 原始语法 12 <%if(age > 18) {%> 13 年龄大于18 14 <% }%> 15 16 // 原始语法 17 <%if (age >18){%> 18 年龄大于18 19 <%}else if(age > 15){%> 20 年龄大于15 21 <%} else {%> 22 年龄不符合要求 23 <%}%>
1 // 导入模板引擎 2 // 返回的template是一个方法 3 const template = require("art-template"); 4 5 const path = require("path"); 6 7 const views = path.join(__dirname,"views","02.art"); 8 // template 方法是用来拼接字符串的 9 // 参数1:模板的路径 绝对路径。绝对路径最后一个为文件名。文件名的后缀要为.art 10 // 参数2:对象,即要在模板中显示的数据 11 // 返回值:拼接好的字符串 12 const html = template(views,{ 13 name:"张三", 14 age:20 15 }); 16 17 console.log(html);
数据循环
1 <!-- 标准语法 --> 2 {{each target}} 3 {{$index}} {{$value}} 4 {{/each}} 5 6 7 <!-- 原始语法 --> 8 <% for(var i = 0; i < target.length; i++){ %> 9 <%= i %> <%= target[i] %> 10 <% } %>
1 <ul> 2 {{each users}} 3 <li> 4 {{$value.name}} 5 {{$value.age}} 6 {{$value.sex}} 7 </li> 8 {{/each}} 9 </ul> 10 11 12 <ul> 13 <% for (var i = 0;i<users.length;i++) {%> 14 <li> 15 <%= users[i].name%> 16 <%= users[i].age%> 17 <%= users[i].sex%> 18 <li> 19 <%}%> 20 </ul>
1 // 导入模板引擎 2 // 返回的template是一个方法 3 const template = require("art-template"); 4 5 const path = require("path"); 6 7 const views = path.join(__dirname,"views","03.art"); 8 // template 方法是用来拼接字符串的 9 // 参数1:模板的路径 绝对路径。绝对路径最后一个为文件名。文件名的后缀要为.art 10 // 参数2:对象,即要在模板中显示的数据 11 // 返回值:拼接好的字符串 12 const html = template(views,{ 13 users:[ 14 { 15 name:"张三", 16 age:20, 17 sex:"男" 18 }, 19 { 20 name:"李四", 21 age:30, 22 sex:"男" 23 }, 24 { 25 name:"王五", 26 age:40, 27 sex:"女" 28 }, 29 { 30 name:"赵六", 31 age:20, 32 sex:"女" 33 } 34 ] 35 }); 36 37 console.log(html); 38 39 /* 40 41 <ul> 42 43 <li> 44 张三 45 20 46 男 47 </li> 48 49 <li> 50 李四 51 30 52 男 53 </li> 54 55 <li> 56 王五 57 40 58 女 59 </li> 60 61 <li> 62 赵六 63 20 64 女 65 </li> 66 67 </ul> 68 69 70 <ul> 71 72 <li> 73 张三 74 20 75 男 76 <li> 77 78 <li> 79 李四 80 30 81 男 82 <li> 83 84 <li> 85 王五 86 40 87 女 88 <li> 89 90 <li> 91 赵六 92 20 93 女 94 <li> 95 96 </ul> 97 98 */
子模板
子模板的作用:可以将网站公共区块(头部、底部)抽离到单独的文件中,在使用子模板语法将这些公共的文件引入即可。
1 <!-- 标准语法 --> 2 {{include '模板路径'}} 3 4 <!-- 原始语法 --> 5 <% include('模板路径') %>
1 // 标准语法 2 {{ include './common/header.art'}} 3 // 原始语法 4 <% include('./common/header.art')%> 5 <div>{{msg}}</div> 6 // 原始语法 7 <% include('./common/footer.art')%> 8 // 标准语法 9 {{ include './common/footer.art'}}
1 // 导入模板引擎 2 // 返回的template是一个方法 3 const template = require("art-template"); 4 5 const path = require("path"); 6 7 const views = path.join(__dirname,"views","04.art"); 8 // template 方法是用来拼接字符串的 9 // 参数1:模板的路径 绝对路径。绝对路径最后一个为文件名。文件名的后缀要为.art 10 // 参数2:对象,即要在模板中显示的数据 11 // 返回值:拼接好的字符串 12 const html = template(views,{ 13 msg:"我是首页" 14 }); 15 16 console.log(html); 17 18 19 /* 20 * 21 输出结果 22 我是头部 23 24 <div>我是首页</div> 25 26 我是底部 27 * */
模板继承
使用模板继承可以将网站HTML骨架抽离到单独的文件中,其他页面模板可以继承骨架文件。
1 <!doctype html> 2 <html> 3 <head> 4 <meta charset="utf-8"> 5 <title>HTML骨架模板</title> 6 // 留下坑让继承的代码去填写 7 {{block 'head'}}{{/block}} 8 </head> 9 <body> 10 // 留下坑让继承的代码填写 11 {{block 'content'}}{{/block}} 12 </body> 13 </html> 14 15 -------------------------------------------------- 16 // 继承代码,填写坑 17 {{extend './layout.art'}}// 继承的代码 18 {{block 'head'}} <link rel="stylesheet" href="custom.css"> {{/block}} 19 {{block 'content'}} <p>This is just an awesome page.</p> {{/block}}
1 // 父模板 2 <!doctype html> 3 <html lang="en"> 4 <head> 5 <meta charset="UTF-8"> 6 <title>Document</title> 7 {{block "link"}} {{/block}} 8 </head> 9 <body> 10 {{block "content"}} {{/block}} 11 </body> 12 </html> 13 14 ---------------------------------------------- 15 // 子模板,用来继承父模板 16 {{extend './common/layout.art'}} 17 18 {{block 'content'}} 19 <p>{{ msg }}</p> 20 {{/block}} 21 22 {{block 'link'}} 23 <link rel="stylesheet" type="text/css" href="./main.css"> 24 {{/block}}
1 // 导入模板引擎 2 // 返回的template是一个方法 3 const template = require("art-template"); 4 5 const path = require("path"); 6 7 8 const views = path.join(__dirname,"views","05.art"); 9 // template 方法是用来拼接字符串的 10 // 参数1:模板的路径 绝对路径。绝对路径最后一个为文件名。文件名的后缀要为.art 11 // 参数2:对象,即要在模板中显示的数据 12 // 返回值:拼接好的字符串 13 const html = template(views,{ 14 msg:"我是首页" 15 }); 16 17 console.log(html);
模板配置
模板配置可以让代码的使用变得简单。并且可以向模板中导入一些方法,和变量在模板中使用。
1,向模板中导入变量 template.defaults.imports.变量名 = 变量值;// 还可以是将一些方法导入到模板中使用
2,设置模板根目录 template.defaults.root = 模板目录;
3,设置模板默认后缀 template.defaults.extname = '.art'
1 // 模板 2 {{ format('yyyy-MM-dd',time)}} 3 4 5 ---------------------------------------------------------- 6 // 配置语法和导入语法 7 const template = require('art-template'); 8 const path = require('path'); 9 10 // 第三方用于处理时间的模块 11 const format = require('date-format'); 12 // 设置模板的根目录 13 template.defaults.root = path.join(__dirname, 'views'); 14 15 // 导入模板变量(方法) 16 template.defaults.imports.format = format; 17 18 // 配置模板的默认后缀 19 template.defaults.extname = ".art"; 20 21 const html = template('06', { 22 time: new Date() 23 }); 24 25 console.log(html);
综合案例
实现功能:
1,建立项目文件夹并生成项目描述文件
2,创建网站服务器实现客户端和服务器端通信
3,连接数据库并根据需求设计学员信息表
4,创建路由并实现页面模板呈递
5,实现静态资源访问
6,实现学生信息添加功能
7,实现学生信息展示功能
第一步:建立项目文件夹并生成项目描述文件
在students文件夹中创建model文件夹,用来存放有关数据库的代码
在students文件夹中创建public文件夹,用来存放静态资源相关的代码
在students文件夹中创建views文件夹,用来存放模板的文件(.art文件里面是HTML代码)
package.json 文件中存放项目描述信息
第二步:创建网站服务器实现客户端和服务器端通信
1 // 引入http模块 2 const http = require("http"); 3 4 // 创建服务 5 const app = http.createServer(); 6 7 // 添加请求事件 8 app.on("request", (req, res) => { 9 // req为请求对象,res为响应对象 10 res.edn("OK"); 11 }); 12 13 app.listen(80); 14 console.log("服务器开启成功");
第三步:连接数据库并根据需求设计学员信息表
1 // 引入数据库模块 2 const mongoose = require("mongoose"); 3 // 连接数据库 4 mongoose.connect("mongodb://localhost/playground",{ useUnifiedTopology: true,useNewUrlParser: true}) 5 .then(()=>console.log("数据库连接成功")) 6 .catch(()=>console.log("连接失败")); 7 8 --------------------------------------------------------------- 9 const mongoose = require("mongoose"); 10 11 // 创建学生的集合规则 12 const studentsSchema = new mongoose.Schema({ 13 name:{ 14 type:String, 15 require:true, 16 minlength:2, 17 maxlength:10 18 }, 19 age:{ 20 type: Number, 21 min:10, 22 max:25, 23 }, 24 sex:{ 25 type:String, 26 }, 27 email:String, 28 hobbies:[String], 29 collage:String, 30 enterDate:{ 31 type:Date, 32 default:Date.now() 33 } 34 }); 35 36 // 使用集合规则创建集合 37 const Student = mongoose.model("Student",studentsSchema); 38 39 // 将学生信息集合进行导出 40 module.exports = Student; 41 42 43 --------------------------------------------------------------------- 44 // 引入http模块 45 const http = require("http"); 46 // querystring 模块 47 const querystring = require("querystring"); 48 // 导入连接数据库模块 49 require("./model/connect"); 50 // 导入学生集合规则构造函数 51 const Student = require("./model/user"); 52 // 创建服务 53 const app = http.createServer(); 54 // 添加请求事件 55 app.on("request", (req, res) => { 56 // req 为请求参数。res为响应参数 57 res.end("OK"); 58 }); 59 60 app.listen(80); 61 console.log("服务器开启成功");
第四步:创建路由并实现页面模板呈递
使用第三方模块router来实现路由,不在自己写路由
功能:实现路由
使用步骤:
1,获取路由对象
2,调用路由对象提供的方法创建路由
3,启用路由,使路由生效
1 // 1,导入第三方模块 2 const getRouter = require('router') 3 // 2,获取路由对象 4 const router = getRouter(); 5 // 3,调用路由对象提供的方法创建路由 6 router.get('/add', (req, res) => { 7 res.end('Hello World!') 8 }) 9 // 启用路由,在事件请求对象中 10 server.on('request', (req, res) => { 11 // 参数1、参数2都为事件请求对象中的参数。参数3位回调函数并且为必选参数,这里不用先写一个空函数 12 router(req, res,()=>{}) 13 })
第五步:实现静态资源访问
使用第三方模块 serve-static。实现静态资源访问服务
步骤:
1,引入serve-static模块获取创建静态资源服务功能的方法
2,调用方法创建静态资源服务并指定静态资源服务目录
3,启用静态资源服务功能
1 // 引入第三方模块,返回的是一个方法 2 const serveStatic = require('serve-static') 3 // 调用该方法创建静态访问。指定静态资源所在文件夹 4 const serve = serveStatic('public') 5 server.on('request', () => { 6 // 开启静态资源访问功能,req,res参数都为事件请求对象的参数。第三个参数为回调函数,必填参数,现在不需要使用,传递一个空函数 7 serve(req, res,()=>{}); 8 }) 9 server.listen(3000)
第六步:实现学生信息添加功能
实现步骤:
1,在模板的表单中指定请求地址与请求方式
2,为每一个表单项添加name属性
3,添加实现学生信息功能路由
4,接收客户端传递过来的学生信息
5,将学生信息添加到数据库中
6,将页面重定向到学生信息列表页面
第七步:实现学生信息展示功能
实现步骤:
1,从数据库中将所有的学生信息查询出来
2,通过模板引擎将学生信息和HTML模板进行拼接
3,将拼接好的HTML模板响应给客户端
--------------------------
--------------------------
1 // 引入数据库模块 2 const mongoose = require("mongoose"); 3 // 连接数据库 4 mongoose.connect("mongodb://localhost/playground",{ useUnifiedTopology: true,useNewUrlParser: true}) 5 .then(()=>console.log("数据库连接成功")) 6 .catch(()=>console.log("连接失败")); 7 8 --------------------------------------------------------------- 9 const mongoose = require("mongoose"); 10 11 // 创建学生的集合规则 12 const studentsSchema = new mongoose.Schema({ 13 name:{ 14 type:String, 15 require:true, 16 minlength:2, 17 maxlength:10 18 }, 19 age:{ 20 type: Number, 21 min:10, 22 max:25, 23 }, 24 sex:{ 25 type:String, 26 }, 27 email:String, 28 hobbies:[String], 29 collage:String, 30 enterDate:{ 31 type:Date, 32 default:Date.now() 33 } 34 }); 35 36 // 使用集合规则创建集合 37 const Student = mongoose.model("Student",studentsSchema); 38 39 // 将学生信息集合进行导出 40 module.exports = Student; 41 42 43 --------------------------------------------------------------------- 44 // 引入http模块 45 const http = require("http"); 46 // 引入router模块 47 const getRouter = require("router"); 48 // 引入path模块 49 const path = require("path"); 50 // 引用静态资源访问模块 51 const serveStatic = require("serve-static"); 52 // 引入模板引擎 53 const template = require("art-template"); 54 // 获取路由对象 55 const router = getRouter(); 56 // 实现静态资源访问 57 const serve = serveStatic(path.join(__dirname, "public")); 58 // querystring 模块 59 const querystring = require("querystring"); 60 // 处理日期模块 61 const dateformat = require("dateformat"); 62 63 // 导入到模板中dateformat方法 64 template.defaults.imports.dateformat= dateformat; 65 66 // 配置模板的根目录 67 template.defaults.root = path.join(__dirname, "views"); 68 69 70 // 创建路由 71 // 呈递学生档案信息页面 72 router.get("/add", (req, res) => { 73 let html = template("index.art", {}); 74 75 res.end(html); 76 }); 77 78 // 呈递学生档案信息列表页面 79 router.get("/list", async (req, res) => { 80 // 查询学生信息 81 let students = await Student.find(); 82 console.log(students); 83 let html = template("list.art", { 84 students:students 85 }); 86 87 res.end(html); 88 }); 89 // 路由:实现post请求的 /add 路由 90 router.post("/add",(req,res)=>{ 91 // 接收post请求参数 92 let formData = ""; 93 94 req.on("data",param =>{ 95 formData += param; 96 }); 97 98 req.on("end",async ()=>{ 99 await Student.create(querystring.parse(formData)); 100 101 res.writeHead(301,{ 102 Location:"/list" 103 }); 104 res.end(); 105 }); 106 }); 107 108 // 导入连接数据库代码 109 require("./model/connect"); 110 // 导入集合构造函数代码 111 const Student = require("./model/user"); 112 // 创建服务器 113 const app = http.createServer(); 114 // 为服务器添加请求事件 115 app.on("request", (req, res) => { 116 // 启用路由 117 router(req, res, () => { 118 }); 119 120 // 启用静态资源访问功能 121 serve(req, res, () => { 122 }); 123 }); 124 125 app.listen(80); 126 console.log("服务器开启成功");
------------