模板引擎教程
其实这个玩意儿也是一个API一个工具,你学习之后知道怎么使用就完事,
其实这个也非常的鸡肋 ,因为所有的渲染都是在后台做的!!!非常非常小的项目,用这个就算了,大的项目还是老老实实写接口我们发现总是去拼接字符串实在是太low了。于是乎我们这样来干,使用模板替代字符串拼接
模板引擎有很多,我们选一个art-template,这个是腾讯开发的,目前运行最快的,引擎是Node的第三方模块
你需要npm下载,然后与大多数的API使用一样,引入然后使用,
主要的使用,给数据 并且制定数据要怎么拼接
简单的使用
- 流程如下
-
在命令行工具中使用 npm install art-template 命令进行下载
-
使用const template = require('art-template')引入模板引擎
-
告诉模板引擎要拼接的数据和模板在哪 const html = template(‘模板路径’, 数据);返回的就是字符串
注意:我们呢的引擎的文件是.art,但是文件的内容还是html格式了,路径是绝对路径 -
使用模板语法告诉模板引擎,模板与数据应该如何进行拼接
- 代码实例
//需求我们把一个对象
const template = require('art-template');
const path = require('path');
const views = path.join(__dirname, 'views', '01.art');
//第二个参数就是在模板里面使用的数据
const html = template(views, {
name: '张三',
age: 20,
content: '<h1>我是标题</h1>'
})
console.log(html);
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<!-- 标准语法 -->
<p>{{ name }}</p>
<p>{{ 1 + 1 }}</p>
<p>{{ 1 + 1 == 2 ? '相等' : '不相等' }}</p>
<p>{{ content }}</p>//这个是原封不动的,不会解析成网页标签
<p>{{@ content }}</p>//解析版
<!-- 原始语法 -->
<p><%= name %></p>
<p><%= 1 + 2%></p>
<p><%= 1 + 1 == 2 ? '相等' : '不相等' %></p>
<p><%= content%></p>
<p><%- content%></p>
</body>
</html>
语法详解:
语法有两种 原始语法 还有 标准语法,两个结合最好,原始的语法里面可以全部都丢js代码
- 大胡子 {{}}
首先是我们的大胡子语法:{{ }} 这个里面的就是我们要输出的东西。其实你可以怎么理解:{{}}里面丢的就是js的代码,
代码实例,注意这里的数据还是上面的那个张三对象
<body>
<!-- 标准语法 -->
<p>{{ name }}</p>
<p>{{ 1 + 1 }}</p>
<p>{{ 1 + 1 == 2 ? '相等' : '不相等' }}</p>
<p>{{ content }}</p>//这个是原封不动的,不会解析成网页标签
<p>{{@ content }}</p>
<!-- 原始语法 -->
<p><%= name %></p>
<p><%= 1 + 2%></p>
<p><%= 1 + 1 == 2 ? '相等' : '不相等' %></p>
<p><%= content%></p>
<p><%- content%></p>
</body>
进行页面渲染
const template = require('art-template');
const path = require('path');
const views = path.join(__dirname, 'views', '01.art');
const html = template(views, {
name: '张三',
age: 20,
content: '<h1>我是标题</h1>'
})
console.log(html);
- 条件判断
这个可以根据条件来渲染页面
你需要明白,这个里面的东西 基本上就是js就完事
基础的语法
if(){
条件成立显示的内容(在这里里面渲染的就是我们html)
}
{{if age > 18}}
年龄大于18
{{else if age < 15 }}
年龄小于15
{{else}}
年龄不符合要求
{{/if}}
<% if (age > 18) { %>
年龄大于18
<% } else if (age < 15) { %>
年龄小于15
<% } else { %>
年龄不符合要求
<% } %>
进行页面渲染
const template = require('art-template');
const path = require('path');
const views = path.join(__dirname, 'views', '01.art');
const html = template(views, {
name: '张三',
age: 20,
content: '<h1>我是标题</h1>'
})
console.log(html);
- 循环
你需要明白,我们拿的数据都是数组或者对象键值对,这种,那么循环渲染就非常重要
数据
onst template = require('art-template');
const path = require('path');
const views = path.join(__dirname, 'views', '03.art');
// 啧啧啧
const html = template(views, {
users: [{
name: '张三',
age: 20,
sex: '男'
}, {
name: '李四',
age: 30,
sex: '男'
}, {
name: '玛丽',
age: 15,
sex: '女'
}]
});
console.log(html);
页面
<ul>
{{each users}}//each //这不就是我们的forEach循环?
<li>
{{$value.name}} //$value就是当前的循环项目,$index就是索引
{{$value.age}}
{{$value.sex}}
{{ $index }}
</li>
{{/each}}
</ul>
<ul>
<% for (var i = 0; i < users.length; i++) { %>
<li>
<%=users[i].name %>
<%=users[i].age %>
<%=users[i].sex %>
</li>
<% } %>
</ul>
- 子模板
说白了就把共同的东西抽离出去
需求:比如把这里,我有一个04页面,然后我需要把common里的三个标签都引入,实现子模板的分离
{{include,'子模板路径,相对路径’}}
04页面结构
{{ include './common/header.art' }}
<% include('./common/header.art') %>
<div> {{ msg }} </div>
{{ include './common/footer.art' }}
<% include('./common/footer.art') %>
footer部分
头部
header部分
底部
layout部分
布局
- 如何进行html结构抽离。模板继承
什么是继承?说的就是把更多的相同的东西头里出来,然后其它人都可以通过继承拿到这个公共部分
要记得在我们的基础模板里面挖坑,因为不同的页面是有不同的骨架内容的
实例代码,挖两个坑,父亲这个是我们首页的首页
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
{{block 'link'}} {{/block}} //这里的link是当前位置(就是你挖的坑的名字)你随便写,一个名字而已
</head>
<body>
{{block 'content'}} {{/block}}
</body>
</html>
继承的模板,儿子
这就是我们的首页
{{extend './common/layout.art'}}
<!-- //继承模板 -->
<!-- //填坑 -->
{{block 'content'}}
<p>{{ msg }}</p>
{{/block}}
{{block 'link'}}
<link rel="stylesheet" type="text/css" href="./main.css">
{{/block}}
数据块
const template = require('art-template');
const path = require('path');
const views = path.join(__dirname, 'views', '04.art');
const html = template(views, {
msg: '我是首页'
});
console.log(html);
- 配置一,导入变量
如何把数据中的日期进行格式化?
我们的方案,用一个方法 处理一下日期就完事了,但是??我们这个方法能不能丢给模板?
大难是可以的,用一个变量把方法的值接过来就完事,注意我们后续基本上使用管道pipe,对于初级程序员是使用这个东西,高级的就使用管道pipe
注意我们去找一个日期处理的工具
npm
使用的步骤:
向模板中导入变量 template.defaults.imports.变量名 = 变量值;
设置模板根目录 template.defaults.root = 模板目录
设置模板默认后缀 template.defaults.extname = '.art'
数据块
const template = require('art-template');
const path = require('path');
const dateFormat = require('dateformat');
// //拼命接路径
// const views = path.join(__dirname, 'views', '04.art');
// 设置模板的根目录,这样我们就不需要拼接路径了
template.defaults.root = path.join(__dirname, 'views');
// 导入模板变量
template.defaults.imports.dateFormat = dateFormat;
// 配置模板的默认后缀
template.defaults.extname = '.html';
const html = template('06.art', {
time: new Date()
});
// 渲染模板 template
// 不写后缀的时候07就会自己去找配置的html后缀
console.log(template('07', {}));
console.log(html);
模板
{{ dateFormat(time, 'yyyy-mm-dd')}}
实战:添加学生档案
以下是项目的目标
注意:你要npm下载一些东西模板引擎啦两个第三方的包啊
重要的事情再说一遍,我们想用返回值的方式 获取异步api的结果,就需要用两个关键字async还有await,要不然你只能用promise.then来干活了,
- 特别说明:
>我们将以一个全栈开发人员的角度去分析还有设计这个小demo,
>
>1.首先我们需要设计数据库
>
>2.其次我们需要设计后台API,也就是写接口
>
>3.最后我们需要作为一名前端开发人员调接口渲染数据
-
业务逻辑分析
- 建立项目文件夹并生成项目描述文件。描述文件?就是那个pack.json
- 创建网站服务器实现客户端和服务器端通信
- 连接数据库并根据需求设计学员信息表
- 创建路由并实现页面模板呈递
- 实现静态资源访问
- 实现学生信息添加功能
- 实现学生信息展示功能
-
我们先来确定使用的技术栈
知识点:http请求响应、数据库、模板引擎、静态资源访问。 -
构建文件夹结构
img
- 建立服务器,设计数据库
这里我们先把数据库模块化出去,然后使用是一个新的api路由api
- common还有user的js
const mongoose = require('mongoose');
// 连接数据库
mongoose.connect('mongodb://localhost/playground', { useNewUrlParser: true })
.then(() => console.log('数据库连接成功'))
.catch(() => console.log('数据库连接失败'))
数据库设计
const mongoose = require('mongoose');
// 创建学生集合规则 设定字段,设计数据库
const studentsSchema = new mongoose.Schema({
name: {
type: String,//类型
required: true,//是否必须
minlength: 2,//最大最小长度等.....
maxlength: 10
},
age: {
type: Number,
min: 10,
max: 25
},
sex: {
type: String
},
email: String,
hobbies: [String],
collage: String,
enterDate: {
type: Date,
default: Date.now
}
});
// 创建学生信息集合
const Student = mongoose.model('Student', studentsSchema);
// 将学生信息集合进行导出
module.exports = Student;
- 知识补充:静态资源访问serve-static
// 使用步骤
// 引入serve-static模块获取创建静态资源服务功能的方法
// 调用方法创建静态资源服务并指定静态资源服务目录
// 启用静态资源服务功能
const serveStatic = require('serve-static')
const serve = serveStatic('public')
server.on('request', () => {
serve(req, res)
})
server.listen(3000)
- app.js
// 引入http模块
const http = require('http');
// 引入模板引擎
const template = require('art-template');
// 引入path模块
const path = require('path');
// 引入静态资源访问模块,拿来主义
const serveStatic = require('serve-static');
// 引入处理日期的第三方模块,实现路由功能的routme
const dateformat = require('dateformat');
const router = require('./route/index');
// 实现静态资源访问服务
const serve = serveStatic(path.join(__dirname, 'public'))
// 配置模板的根目录
template.defaults.root = path.join(__dirname, 'views');
// 处理日期格式的方法
template.defaults.imports.dateformat = dateformat;
// 数据库连接
require('./model/connect');
// 创建网站服务器
const app = http.createServer();
// 当客户端访问服务器端的时候
app.on('request', (req, res) => {
// 启用路由功能
router(req, res, () => {})
// 启用静态资源访问服务功能
serve(req, res, () => {})
});
// 端口监听
app.listen(80);
console.log('服务器启动成功');
- 路由的简要的语法
//步骤
// 1.获取路由对象
// 2.调用路由对象提供的方法创建路由
// 3.启用路由,使路由生效
const getRouter = require('router')
const router = getRouter();
router.get('/add', (req, res) => {
res.end('Hello World!')
})
server.on('request', (req, res) => {
router(req, res)
})
- roter下的路由,业务处理,先测试接口,再渲染数据,注意我们的渲染都是在后台里面做的,并不是真正的写接口,这一点你需要明白
// 引入router模块//专门处理路由的一个第三方模块
const getRouter = require('router');
// 获取路由对象
const router = getRouter();
// 学生信息集合
const Student = require('../model/user');
// 引入模板引擎
const template = require('art-template');
// 引入querystring模块,你是否还接这个是什么?这个就是处理我们的post请求数据的!
const querystring = require('querystring');
// 呈递学生档案信息页面
router.get('/add', (req, res) => {
let html = template('index.art', {});
res.end(html);
})
// 呈递学生档案信息列表页面
router.get('/list', async(req, res) => {
// 查询学生信息
let students = await Student.find();
console.log(students);
let html = template('list.art', {
students: students
})
// res.end(students )//测试接口
res.end(html )
})
// 实现学生信息添加功能路由
router.post('/add', (req, res) => {
// 接收post请求参数
let formData = '';
req.on('data', param => {
formData += param;
});
req.on('end', async() => {
await Student.create(querystring.parse(formData))
res.writeHead(301, {
Location: '/list'
});
// 测试接口
res.end( 'ok' )
})
});
module.exports = router;
- 渲染,我们其实是在服务器里面做的渲染,这里的耦合度太高了,后期我们会把前后台都分开
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>学员信息</title>
<link rel="stylesheet" href="./css/list.css">
</head>
<body>
<table>
<caption>学员信息</caption>
<tr>
<th>姓名</th>
<th>年龄</th>
<th>性别</th>
<th>邮箱地址</th>
<th>爱好</th>
<th>所属学院</th>
<th>入学时间</th>
</tr>
{{each students}}
<tr>
<th>{{$value.name}}</th>
<th>{{$value.age}}</th>
<th>{{$value.sex == '0' ? '男' : '女'}}</th>
<th>{{$value.email}}</th>
<th>
{{each $value.hobbies}}
<span>{{$value}}</span>
{{/each}}
</th>
<th>{{$value.collage}}</th>
<th>{{dateformat($value.enterDate, 'yyyy-mm-dd')}}</th>
</tr>
{{/each}}
</table>
</body>
</html>
总结:
思路非常的重要,路由的get是在请求页面, post是在发数据
虽然我们没有前后台分离,但是我希望你能明白如何用Node写接口,这个技能还是蛮重要的!
关于接口的测试工具:postman,以下是我在这个小demo中的一些测试接口的截图