Node.js-day04
模板引擎
模板引擎可以让将数据和HTML模板更加友好的结合,省去繁琐的字符串拼接,使代码更加易于维护。
art-template模板引擎
高性能 JavaScript 模板引擎,使用 npm install art-template 命令下载。
入门使用
创建 js 文件,引入 art-template 库
const trempalte = require('art-template');
引入拼接的数据源
// 引入path库
const path = require('path');
// 拼接路径,这里最好用绝对路径
const views = path.join(_dirName,'views','index.art');
// 关联到 template里面
const html = template(views,{
name: '马超'
});
创建 .art 渲染模板
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<!--标准语法-->
<p>{{ name }}</p>
<!--原生语法-->
<p><%= age%></p>
</body>
</html>
模板语法
通过模板引擎提供的特殊语法,告知模板引擎数据和模板具体的拼接细节。
插值表达式
即{{}},用来显式数据,将数据变量放入双大括号之中即可。
原始语法
<% %>
标准语法用 {{}}
在大括号里面可以进行逻辑运算
<p>{{ 1 + 1 }}</p>
<p>{{ 1 + 1 == 2 ? '相等' : '不相等' }}</p>
<p>{{ content }}</p>
如果说需要解析html标签,需要在变量前面加 @ 符号
<p>{{@ content }}</p>
原生语法 <%= %>
可以进行逻辑运算
<p><%= 1 + 2%></p>
<p><%= 1 + 1 == 2 ? '相等' : '不相等' %></p>
<p><%= content%></p>
如果说需要解析html标签,需要在变量前面加 - 符号
<p><%- content%></p>
条件判断
**标准语法 {{if 条件}} … {{/if}} **
{{if age > 18}}
年龄大于18
{{else if age < 15 }}
年龄小于15
{{else}}
年龄不符合要求
{{/if}}
原生语法 <% if (value) { %> … <% } %>
<% if (age > 18) { %>
年龄大于18
<% } else if (age < 15) { %>
年龄小于15
<% } else { %>
年龄不符合要求
<% } %>
循环
标准语法 {{each 数据}} {{/each}}
<ul>
{{each users}}
<li>
{{$value.name}}
{{$value.age}}
{{$value.sex}}
</li>
{{/each}}
</ul>
原生语法 <% for() { %> <% } %>
<ul>
<% for (var i = 0; i < users.length; i++) { %>
<li>
<%=users[i].name %>
<%=users[i].age %>
<%=users[i].sex %>
</li>
<% } %>
</ul>
子模版
使用子模板可以将网站公共区块(头部、底部)抽离到单独的文件中
标准语法 {{include ‘模板’}}
{{ include './common/header.art' }}
...
{{ include './common/footer.art' }}
原生语法 <%include(‘模板’) %>
<% include('./common/header.art') %>
...
<% include('./common/footer.art') %>
模板继承
使用模板继承可以将网站HTML骨架抽离到单独的文件中,其他页面模板可以继承骨架文件
但是在html骨架中,有一些内容是不一样的,例如引入的css不同,引入的js脚本不同,所以我们可以通过在骨架中先预留几个位置,让其它功能页面在继承的使用,引入相应自己的文件即可
使用
现在骨架标签中设定预留位置
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>HTML骨架模板</title>
<!-- 预留位置,打上标记为 head-->
{{block 'head'}}{{/block}}
</head>
<body>
<!-- 预留位置,打上标记为 content-->
{{block 'content'}}{{/block}}
</body>
</html>
在另外的 模板文件中利用 extends 来进行引入
<!--index.art 首页模板-->
<!--extend 进行继承, 后面跟需要继承的文件路径-->
{{extend './layout.art'}}
{{block 'head'}} <link rel="stylesheet" href="custom.css"> {{/block}}
{{block 'content'}} <p>{{name}}</p> {{/block}}
在js文件里面输入内容,利用art-templare 进行模板渲染
//引入 template 库
const template = require('art-template');
//引入 path 库,用来处理路径
const path = require('path');
//生成路径
const views = path.join(_dirName,'views','index.art');
//利用template 进行渲染
const html = template(views,{
name: '马超'
});
模板配置
在模板引擎中,如果想使用第三方模块的一些方法,默认我们是不能直接使用的,必须要通过template模块给我们提供的方法,把第三方模块的对象当作变量传递进入
下载第三方模块 npm install dateformat
语法:
template.defaults.imports.自定义变量名 = 第三方模板对象;
示例代码
//1. 需要先 下载第三方模块 npm install dateformat
//2. 模板引擎第三方库
const template = require('art-template');
//3. 处理路径的第三方模块
const path = require('path');
const views = path.join(__dirname, 'views', 'index.art');
//4. 格式化日期的第三方模块
const dateFormart = require('dateformat');
//5. 不能直接使用,需要通过 template进行模板配置
template.defaults.imports.dateFormart = dateFormart;
const html = template(views, {
time: new Date(),
})
console.log(html);
渲染模板
{{extend './common/layout.art'}}
{{block 'css'}}
<link href='style.css' />
{{/block}}
{{block 'content'}}
<p>{{ dateFormart(time,'yyyy-MM-dd hh:mm:ss') }}</p>
{{/block}}
输出结果
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<link href='style.css' />
</head>
<body>
<p>2019-22-16 01:04:17</p>
</body>
</html>
设置模板根目录
有的时候我们引入模板会比较多,如果一个一个去进行引入比较麻烦,所以我们可以通过引入模板根目录的形式去进入,这样当我们引入模板文件的时候,它会根据我们传递的名字自动匹配
语法:
template.defaults.root = path.join(__dirname, 模板文件夹名称);
设置模板默认后缀
可以去设置默认的后缀名,这样我们引入文件省略后缀名
语法:
template.defaults.extname = '.html';
案例介绍 – 学生档案管理
效果图
制作流程
- 建立项目文件夹并生成项目描述文件
- 创建网站服务器实现客户端和服务器端通信
- 连接数据库并根据需求设计学员信息表
- 创建路由并实现页面模板呈递
- 实现静态资源访问
- 实现学生信息添加功能
- 实现学生信息展示功能
model 放置数据库相关代码
pulic 静态资源代码
router 路由代码
views 模板文件
app.js 入口主要文件
app.js 入口主要文件
// 引入 http 模块
const http = require('http');
// 引入模板引擎
const template = require('art-template');
// 引入path模块
const path = require('path');
const router = require('./router/index');
// 引入静态资源访问模块
const serveStatic = require('serve-static');
// 引入处理日期的第三方模块
const dateFormat = require('dateformat');
// 实现静态资源访问服务
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, () => {})
});
// 监听80端口
app.listen(80);
console.log('服务器启动成功');
model 放置数据库相关代码
// connect.js 文件
const mongoose = require('mongoose');
//连接数据库
mongoose.connect('mongodb://localhost/mc', { useNewUrlParser: true })
.then(() => console.log('数据库连接成功'))
.catch(() => console.log('连接数据库失败'))
// user.js 文件
const mongoose = require('mongoose');
// 创建学生集合规则
const studentsSchema = new mongoose.Schema({
name: {
// 类型
type: String,
// 是否是必须要填写
required: true,
// 最小长度
minlength: 2,
// 最大长度
maxlength: 16
},
age: {
type: Number,
// 最小值
min: 18,
// 最大值
max: 30
},
sex: {
type: String
},
email: String,
// 爱好,数组形式
hobbies: [String],
collage: String,
enterDate: {
type: Date,
// 默认时间是当前时间
default: Date.now
}
});
// 创建学生信息集合
const Student = mongoose.model('Student', studentsSchema);
// 将学生信息集合进行导出
module.exports = Student;
router 路由代码
// 引用router模块
const getRouter = require('router');
// 获取路由对象
const router = getRouter();
// 引入模板引擎
const template = require('art-template');
// 引入queryatring模块
const querystring = require('querystring');
// 学生信息集合
const Student = require('../model/user');
// 呈现学生档案信息页面
router.get('/add', (req, res) => {
let html = template('index.art', {});
res.end(html);
});
/ 呈现学生档案信息列表页面
router.get('/list', async(req, res) => {
let students = await Student.find()
let html = template('list.art', {
students: students
})
res.end(html);
});
//用户提交数据的处理
router.post('/add', (req, res) => {
// 接收用户提交信息
let formData = '';
// 正在接收数据
req.on('data', parem => {
formData += parem;
})
// post参数接收完毕
req.on('end', async() => {
// 利用 querystring来进行数据的解析
// 将用户提交的信息添加到数据库中
await Student.create(querystring.parse(formData));
// 301 代表重定向
// location 跳转地址
res.writeHead(301, {
Location: '/list'
});
res.end()
})
});
module.exports = router;
views 模板文件
// index.art 文件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
<title>学生档案</title>
<link rel="stylesheet" href="./css/main.css">
</head>
<body>
<form action="/add" method='post'>
<fieldset>
<legend>学生档案</legend>
<label>
姓名: <input class="normal" type="text" autofocus placeholder="请输入姓名" name='name'>
</label>
<label>
年龄: <input class="normal" type="text" placeholder="请输入年龄" name='age'>
</label>
<label>
性别:
<input type="radio" value="0" name='sex'> 男
<input type="radio" value="1" name='sex'> 女
</label>
<label>
邮箱地址: <input class="normal" type="text" placeholder="请输入邮箱地址" name='email'>
</label>
<label>
爱好:
<input type="checkbox" value="敲代码" name='hobbies'> 敲代码
<input type="checkbox" value="打篮球" name='hobbies'> 打篮球
<input type="checkbox" value="睡觉" name='hobbies'> 睡觉
</label>
<label>
所属学院:
<select class="normal" name='collage'>
<option value="前端与移动开发">前端与移动开发</option>
<option value="PHP">PHP</option>
<option value="JAVA">JAVA</option>
<option value="Android">Android</option>
<option value="IOS">IOS</option>
<option value="UI设计">UI设计</option>
<option value="C++">C++</option>
</select>
</label>
<label>
入学日期: <input type="date" class="normal" name='enterDate'>
</label>
<label class="btn">
<input type="submit" value="提交" class="normal">
</label>
</fieldset>
</form>
</body>
</html>
// liat .art 文件
<!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>
案例相关第三方模块
router
根据路由功能来进行请求路径的分发,我们如果去进行路由的编写比较的繁琐,这里利用到一个第三方的库,来帮我们做路由的分发 router
// 1. 下载对应的第三方模块 npm install router
// 2. 通过 require来进行模块的引入
const getRouter = require('router');
// 3. 通过 getRouter() 方法获取路由对象
const router = getRouter();
// 4. 在我们监听的请求函数里面开启路由功能
server.on('request', (req, res) => {
//第三个参数必须要带上
router(req,res,()=>{
//这个函数是我们路由分发完毕后,再会调用此函数
});
});
//5. 进行代码编写,第三方库里面帮我们定义好了 get方式请求的处理和post方式请求的处理
router.get('/index', (req, res) => {
console.log('index 请求成功');
res.end('index 请求成功');
})
router.get('/list', (req, res) => {
console.log('list 请求成功');
res.end('list 请求成功');
})
使用静态资源第三方库 serve-static
此时还没有完成,因为在html里面进行了css的引入,这里我们需要需要把一些静态资源引入进来,我们可以通过第三方模块来实现 serve-static
1.下载第三方模块 npm install serve-static
2.引入 serve-static 模块获取创建静态资源服务功能的方法
3.调用方法创建静态资源服务并指定静态资源服务目录
4.启用静态资源服务功能
//1.引入静态资源加载的模块
const serveStatic = require('serve-static');
//2.得到静态资源加载对象 传递静态资源的路径,方便后续使用
const static = serveStatic(path.join(__dirname, 'public'));
server.on('request', (req, res) => {
...
//3.开启静态资源
static(req, res, () => {});
});