续 Express 新手入坑笔记之动态渲染 html, 上一篇只是初步实现了 HTML 的动态渲染, 但不够灵活, 如果写一个动态网站, 会遇到大量模板复用的场景, 为每个 url 写一个单独的 HTML 文件是非常耗时耗力的, 而且可维护性也不好, Handlebars(以下简称 hbs)为我们提供了继承模板 (类似 django 的 extend) 和插入代码块 (类似 django 的 include) 的方法, 下面我来做一个演示
模板布局的继承
网站有多个网页, 网页的布局大致相同, 头部和底部可能是通用的, 我们可以为所有网页设置一个默认的布局
- // 配置模板引擎, 设置默认的模板布局
- App.engine('html', exphbs({
- layoutsDir: "views/layouts/",
- defaultLayout: 'layout-header-footer.html',
- extname: '.html'
- }));
- // 根路由对应的页面, 启用默认模板布局
- App.get('/', function(req, res) {
- res.render('index', {
- title: "首页",
- personInfoList: [{
- name: "王炮儿(一拳超人)",
- age: 20
- }, {
- name: "炮姐(御坂美琴)",
- age: 15
- }]
- });
- });
在 views 文件夹下新建 layouts 文件夹, 在 layouts 文件夹新建 layout-header-footer.HTML 作为模板, 在 layout-header-footer.HTML 内写入以下代码:
- <!DOCTYPE HTML>
- <HTML lang="en">
- <head>
- <meta charset="UTF-8">
- <title>
- {{title}}
- </title>
- </head>
- <body>
- <style>
- body{ margin: 0; padding: 0; }
- </style>
- <header style="width: 100%; height: 80px; text-align: center; line-height: 80px; background-color: #44A1F8; color: #ffffff;">
- 这是头部
- </header>
- {{{body}}}
- <footer style="position: fixed; bottom:0; width: 100%; height: 80px; text-align: center; line-height: 80px; background-color: #64B587; color: #ffffff;">
- 这是底部
- </footer>
- </body>
- </HTML>
将 views 文件夹下, index.HTML 内的内容精简(只保留关键内容 body)
- <h1 style="color: #64B587">人物介绍</h1>
- {{#each personInfoList}}
- <h2 > 昵称:{{this.name}}</h2>
- <h2 > 年龄:{{this.age}}</h2>
- <hr>
- {{/each}}
重新访问根路由
有些网页可能比较特别, 只需要显示通用的底部
在 layouts 文件夹内, 新建 layout-footer.HTML 作为模板(顾名思义, 与上面的通用模板,
layout-header-footer.HTML
相比, layout-footer.HTML 只有底部内容), layout-footer.HTML 内的内容为:
- <!DOCTYPE HTML>
- <HTML lang="en">
- <head>
- <meta charset="UTF-8">
- <title>
- {{title}}
- </title>
- </head>
- <body>
- <style>
- body{ margin: 0; padding: 0; }
- </style>
- {{{body}}}
- <footer style="position: fixed; bottom:0; width: 100%; height: 80px; text-align: center; line-height: 80px; background-color: #64B587; color: #ffffff;">
- 只有底部
- </footer>
- </body>
- </HTML>
编写 / about 路径的处理函数, 让 / about 对应的网页套用 layout-footer.HTML 模板
- // 匹配 / about 路由
- App.get('/about', function(req, res) {
- res.render('about', {
- layout: "layout-footer.html"
- });
- });
在 views 下, 编写 about.HTML 文件
<h1 > 关于</h1>
访问
http://localhost:3000/about
, 效果如图所示
以上, 我们已经实现了默认模板布局和
个性化模板布局
的编写和使用, 但在实际开发中, 我可能会遇到在某个页面内, 引入代码块的需求, 比如插入广告位! 下面我们来完成引入广告位的实例~
引入代码块
需求: 引入广告位
在 views 文件夹下新建 partials 文件夹, 在 partials 内新建 ad.HTML, 在 ad.HTML 内编写广告代码
<div style="width: 100%; height: 20px; text-align: center; font-size: 12px; line-height: 20px; color: #413F43; background-color: #F0BB40;">这是一段广告</div>
在 express-simple-server.JS 中配置
广告代码所在的目录
- // 配置模板引擎
- App.engine('html', exphbs({
- + partialsDir: 'views/partials/',
- layoutsDir: "views/layouts/",
- defaultLayout: 'layout-header-footer.html',
- extname: '.html'
- }));
修改 abou.HTML, 插入广告代码
- <h1>
- 关于
- </h1>
- {{>ad}}
查看插入效果
express-simple-server.JS 最终代码
- const express = require('express');
- const exphbs = require('express-handlebars');
- const App = express();
- // 配置模板引擎
- App.engine('html', exphbs({
- partialsDir: 'views/partials/',
- layoutsDir: "views/layouts/",
- defaultLayout: 'layout-header-footer.html',
- extname: '.html'
- }));
- App.set('view engine', 'html');
- // 如果在环境变量内, 设定了程序运行端口, 则使用环境变量设定的端口号, 否则使用 3000 端口
- App.set('port', process.env.PORT || 3000);
- // 匹配静态文件目录
- App.use(express.static(__dirname + '/public'));
- // 匹配根路由 / (如果不特别指明返回的状态码, 则默认返回 200)
- App.get('/', function(req, res) {
- res.render('index', {
- title: "首页",
- personInfoList: [{
- name: "王炮儿(一拳超人)",
- age: 20
- }, {
- name: "炮姐(御坂美琴)",
- age: 15
- }]
- });
- });
- // 匹配 / about 路由
- App.get('/about', function(req, res) {
- res.render('about', {
- layout: "layout-footer.html"
- });
- });
- // 定制 404 页面 (返回 404 状态码)
- App.use(function(req, res) {
- let currentTime = new Date();
- res.type('text/plain');
- res.status(404);
- res.send('404 - 你访问的页面可能去了火星 \ n' + currentTime);
- });
- // 定制 500 页面 (返回 500 状态码)
- App.use(function(err, req, res, next) {
- let currentTime = new Date();
- let errInfo = err.stack;
- res.type('text/plain');
- res.status(500);
- res.send('500 - 服务器发生错误 \ n' + 'errInfo:' + errInfo + '\n' + 'currentTime:' + currentTime);
- });
- // 监听服务端口, 保证程序不会退出
- App.listen(App.get('port'), function() {
- console.log('Express 服务正在运行在 http://localhost:' + App.get('port') + '; 按 Ctrl-C 关闭服务.');
- })
小结:
如果你了解 django 的模板继承 (extend) 和代码插入 (include) 的规则, 会发现 hbs 也是类似的, 其实 hbs 还有名为 helper 的玩法, 可以更加灵活插入 CSS, JS, HTML, 有兴趣可以自己了解下, 或者等我后续的更新
来源: http://www.jianshu.com/p/463d3e85d385