Express学习 ------模版引擎(handlebars)
Handlebars一款js模版引擎,我们在做客户端开发的时候,也可能已经使用过。它语法比较简单,和我们平常写的html 一样,只不过html 中可以加入handlebars 表达式。 handlebars表达式用 {{variable}} 表示,当程序运行的时候,变量就被传进来的数据代替。下面就是一个比较简单的模版:
- <header>
- <h2>{{title}}</h2>
- <p>{{content}}</p>
- </header>
当我们传递一个对象数据(如下)给这个模板的时候,
- <script>
- var context = {
- title:"My New Post",
- content: "This is first post"
- }
- </script>
它就会被解析为
- <header>
- <h2>My New Post</h2>
- <p>This is first post</p>
- </header>
非常简单,除了几个表达式,就是html 代码,当然,这也展示的它的特点,模板和数据分开,只定义视图,即需要展示给用户看的部分。
Express 默认不支持Handlebars 模板,但我们可以通过 安装express-handlebars 第三方插件来进行支持,创建一个项目来体验一下 express和 handlebar.
新建express 文件夹,npm init -y 快速建立 package.json 文件,安装 express 和 express-handlebars(npm install express express-handlebars -S). 再新建 server.js 作为项目的启动文件,views 文件夹作为 模版存放的地方,下面再建两个文件夹 layouts 和partials, 这两个文件夹的作用后面再说,先放这里。 目录如下:
首先用express 搭建http 服务器(如下),在当前文件夹中调用cmd命令窗口,输入node server, 然后在浏览器地址栏中输入localhost:8080, 可以看到hello world ,表明服务器搭建成功
- var express = require('express'),
- app = express();
- app.use(function (req,res) {
- res.send("hello world")
- })
- app.listen(8080);
由于 express 不支持Handlebars 模板,我们先要注册该模板引擎,调用app.engine() 方法来进行,express-handlebar 提供了两种方式来注册handlebars ,简单的看一下express-handlebars 里面 index.js 的源码
- var ExpressHandlebars = require('./lib/express-handlebars');
- exports = module.exports = exphbs;
- exports.create = create;
- exports.ExpressHandlebars = ExpressHandlebars;
- // -----------------------------------------------------------------------------
- function exphbs(config) {
- return create(config).engine;
- }
- function create(config) {
- return new ExpressHandlebars(config);
- }
在项目中使用express-handlebars, 就需要引入它。 server.js 中 var exphbs =require('express-handlebars'); 引入它。当我们引入时,node 就会从node_module 中查找我们安装的模块,如果是一个文件夹,node 就会去查找该文件夹下的 index.js文件。我们看一下node_modules, express-handlebars 是一个文件夹,打开文件夹,可以看到index.js, 就是上面的源码,可以看到它暴露出了 exphbs 函数,我们的定义的变量exphbs 就是指向这个函数,它还可以接受一个配置参数。我们可以调用这个函数进行配置
- var express = require('express'),
- app = express();
- // 引入express-handlebars
- var exphbs = require("express-handlebars")
- app.engine("handlebars", exphbs({
- defaultLayout: "main"
- }))
- app.listen(8080);
app.engine 接受两个参数,一个是名字,这很好理解,注册肯定要给它起个名字,以便后面使用。第二个是函数,必须符合express 注册模版的规范,我们按照这个模式写,就可以了。它有好多配置选项,这只写了一个。
我们看到它还有一个create 方法,我们也可以用这种方式进行配置
- app.engine('handlebars', exphbs.create({
- defaultLayout: "main",
- layoutDir: app.get('views') + '/layouts',
- partialsDir:[app.get('views') + '/partials']
- }).engine)
上面这种写法,可能写的不太好理解,我们把它拆分一下, 又增加了两个配置项
- var hbs = exphbs.create({
- defaultLayout: "main",
- layoutDir: app.get('views') + '/layouts',
- partialsDir:[app.get('views') + '/partials']
- });
- app.engine('handlebars', hbs.engine);
不管用哪种方法,我们都成功注册了handlebars模版,现在我们要告诉express来使用 handlerbars, 调用app.set 方法, 第二个参数是我们注册的模板的名字,就是app.engine中第一个参数,他们要保证一致
- app.set(“view engine”, 'handlebars' )
最后还要告诉express 我们的模版文件放在什么地方,以便express 去查找使用,还是要调用app.set() 方法
- app.set("views", __dirname+ "/views"); // 第一个参数views是复数,一定不忘记后面的还有一个s, 要不然会报 View is not a construction
现在我们可以使用handlebar 模版引擎了,再来看一个注册模版擎时的参数 defaultLayout, layoutDir,partialsDir。default Layout, 默认布局, layout directory, 布局文件所在的目录,partial directory
局部文件所在的目录。 根据字面意思,我们也可以得到 defaultLayout: 设置默认布局文件,layoutDir 设置布局文件所在的位置,partialsDir 设置局部文件所在的位置。
我们需要了解一下handlebars 中的基本概念 : 布局,局部, 还有视图。
视图(views): 就是我们定义的任何的模板片段。 app.set("views", __dirname+ "/views"), 我们已经设置我们的视图文件所放的位置,就是views文件夹下。我们在于views 文件夹下定义一个 视图,index.handlebars
<div class="panel panel-primary">
<div class="panel-heading">
<h3 class="panel-title">欢迎使用handlebars</h3>
</div>
</div>
布局:也是一种模版,不过作用比较特殊,所以单独列出来。想一下我们的网站,主要分为header ,main, footer 三个部分,通常header ,footer 部分是不变的,只有main 是经常改变的, 程序在运行的过程中,只要动态的替换掉main 就可以了。这时我们就可以定义一个文件,包含不变的header, footer 和 可变的main,这个文件就是布局。在注册handlebars的时候,我们设置 defaultLayout 为main,其实是main.handlebars, 只不过是 省略了后缀名,并且设置 layoutDir( 布局文件所在的位置)为views文件夹下 layouts文件夹,那么就在 layouts文件夹新建main.handlebars 文件
- <!doctype>
- <html>
- <head>
- <title>Meadowlark Travel</title>
- <link rel="stylesheet" href="/css/main.css">
- </head>
- <body> {{{body}}} </body>
- </html>
A layout is simply a Handlebars template with a {{{body}}}
placeholder. Usually it will be an HTML page wrapper into which views will be rendered. 官网也说了,布局也是模版,只不过它 带有{{{body}}} 占位符,我们的view 就会渲染在{{{body}}}占位符所在的地方。
局部文件(partial):有些时候,有几个页面要共用相同的部分,如侧边栏这,我们通常都会封装为组件,然而在handlebars 中,它们称之为局部文件partial,可以知道局部文件也是代码片段。我们在注册模版引擎的时候,设置 partialsDir(局部文件所在的路径)为views 下面的 partials文件夹,所以我们在partials文件夹下面建一个局部文件,命名为partial.handlebars
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">侧边栏</h3>
</div>
</div>
局部文件是几个页面要共用部分,它也应该包含在布局中。 在布局中,如何使用? {{> partial}} >加局部文件的名称,增加bootstrap
- <!DOCTYPE html>
- <html>
- <head>
- <meta charset="UTF-8">
- <title>Express Handlebars 使用</title>
- <link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" >
- </head>
- <body>
- <div class="container">
- <div class="row">
- <div class="col-sm-8">
- {{{ body }}}
- </div>
- <div class="col-sm-4">
- {{> partial }}
- </div>
- </div>
- </div>
- </body>
定义的视图,布局,局部文件,我们怎么使用呢?这要用到render方法,去渲染模版。render 方法是定义在res 响应对象上的,所以我们浏览器端发起一个请求,让它输出动态模版,所以我们在 server.js 中定义一个路由,
整个server.js如下
- var express = require('express'),
- app = express();
- // 引入express-handlebars
- var exphbs = require("express-handlebars")
- // 设置模板存放路径
- app.set("views", __dirname+ "/views")
- // 注册handlebars模板引擎
- var hbs = exphbs.create({
- defaultLayout: "main",
- layoutDir: app.get('views') + '/layouts',
- partialsDir:[app.get('views') + '/partials']
- });
- app.engine('handlebars', hbs.engine);
- // 告诉express使用handlebars模板,
- // 第二个参数是我们注册的模板的名字,就是app.engine中第一个参数,他们要保证一致
- app.set('view engine', 'handlebars' )
- // render 渲染模板
- app.get('/', function (req,res) {
- res.render('index')
- })
- app.listen(8080);
render方法,接受一个参数,那就是要渲染的模版(视图)的名字,当exrpess 执行render 的时候,它会从views 文件夹下找到我们指定的文件,然后再找到布局文件,替换掉里面的{{{body}}},如果有partial, 它还会从particals 文件夹下找到局部文件,进行合并,形在一个完整的html文件进行输出。这也就是我们上面一系列设置默认文件夹的原因。
我们每次渲染一个视图文件时,都会结合layout 布局模版渲染, 有时我们并不需要layout布局模版,这时可以在render 方法中进行设置 layout: false
- app.use(function (req,res) {
- res.render('404', {
- layout: false
- });
- })
在设置模版引擎的时候,我们只指定了一个默认的布局视图,如果我们带想使用其他视图,怎么办? 调用render 方法的时候,指定layout,当然要确保这个layout文件在layout文件夹中。
- app.get('/foo', function(req, res){
- res.render('foo', { layout: 'microsite' });
- })
现在我们页面都是静态的,没有任何改变。现在在index.handlbars 增加一个日期,{{time}}
- <div class="panel panel-primary">
- <div class="panel-heading">
- <h3 class="panel-title">
- <!-- 增加 time -->
- 欢迎使用handlebars模板 <small>{{timeFormate time}}<small>
- </h3>
- </div>
- </div>
那么我们在渲染的时候要给time传递参数, render 方法可以接受第二个可选参数,它是一个对象, 就是我们向模版中传递的数据,对象的属性就是我们在模版中定义的表达式,如time
- res.render('index' , {
- time: Date.now()
- })
这时我们发现,页面中显示的日期,但它是日期毫秒数,我们想把他转化成年月日的形式,这就要执行一定的逻辑操作,但是handlebars不支持在模版中使用逻辑的,这时要用到 helper 助手。它其实是一个函数,对模版中的表达式执行逻辑操作, helper 在模版中使用之前要先注册。这时有两种方法,
一种是 在注册handlebars 模版引擎的时候,直接给它配置helpers
- var hbs = exphbs.create({
- defaultLayout: "main",
- layoutDir: app.get('views') + '/layouts',
- partialsDir:[app.get('views') + '/partials'],
- // 增加helpers
- helpers: {
- timeFormate: function (time) {
- var dateTime = new Date(time)
- return dateTime.getFullYear() +"年"+ (dateTime.getMonth()+1)+ "月" +
- dateTime.getDay() +'日'
- }
- }
- });
一种是在调用render 方法的时候给它配置helpers
- app.get('/', function (req,res) {
- res.render('index' , {
- time: Date.now(),
- //配置helpers
- helpers : {
- timeFormate: function (time) {
- var dateTime = new Date(time)
- return dateTime.getFullYear() +"年"+ (dateTime.getMonth()+1)+ "月" +
- dateTime.getDay() +'日'
- }
- }
- })
- })
上面的第一种配置方式,可以叫做全局配置,因为它在所有的模版文件中都可以使用,下面的一种则只能在 index模版中使用,可以叫做局部配置。
定义了helpers, 我们模版中就可以使用了,使用也简单,只要在模版的表达式前面加上就可以了。
- <div class="panel panel-primary">
- <div class="panel-heading">
- <h3 class="panel-title">
- <!-- 增加 timeFormate helper -->
- 欢迎使用handlebars模板 <small>{{timeFormate time}}<small>
- </h3>
- </div>
- </div>
express-handlebars还支持子目录, 所以如果你有大量的局部文件,可以将它 们组织在一起。例如,你有一些社交媒体局部文件,可以将它们放在views/ partials/social 目录下面, 然后使用{{> social/facebook}}、{{> social/twitter}} 等来引入它们。
Express学习 ------模版引擎(handlebars)的更多相关文章
- js模版引擎handlebars.js实用教程
js模版引擎handlebars.js实用教程 阅读本文需要了解基本的Handlebars.js概念,本文并不是Handlebars.js基础教程,而是注重于实际应用,为读者阐述使用过程中可能会遇到的 ...
- 模版引擎Handlebars和Mustache
Handlebars是一款很高效的模版引擎,提供语意化的模版语句,最大的兼容Mustache模版引擎, 提供最大的Mustache模版引擎兼容, 无需学习新语法即可使用; 下面这个是基本的模版表达式, ...
- js模版引擎handlebars.js实用教程——为什么选择Handlebars.js
返回目录 据小菜了解,对于java开发,涉及到页面展示时,比较主流的有两种解决方案: 1. struts2+vo+el表达式. 这种方式,重点不在于struts2,而是vo和el表达式,其基本思想是: ...
- js模版引擎handlebars.js实用教程——each-基本循环使用方法
返回目录 <!DOCTYPE html> <html> <head> <META http-equiv=Content-Type content=" ...
- js模版引擎handlebars.js实用教程——each-循环中使用this
返回目录 <!DOCTYPE html> <html> <head> <META http-equiv=Content-Type content=" ...
- js模版引擎handlebars.js实用教程——each嵌套
<!DOCTYPE html> <html> <head> <META http-equiv=Content-Type content="text/ ...
- js模版引擎handlebars.js实用教程——循环中使用索引
<!DOCTYPE html> <html> <head> <META http-equiv=Content-Type content="text/ ...
- js模版引擎handlebars.js实用教程——with-进入到某个属性(进入到某个上下文环境)
返回目录 <!DOCTYPE html> <html> <head> <META http-equiv=Content-Type content=" ...
- js模版引擎handlebars.js实用教程——with-终极this应用
返回目录 <!DOCTYPE html> <html> <head> <META http-equiv=Content-Type content=" ...
随机推荐
- 线程安全之CAS机制详解(分析详细,通俗易懂)
背景介绍:假设现在有一个线程共享的变量c=0,让两个线程分别对c进行c++操作100次,那么我们最后得到的结果是200吗? 1.在线程不安全的方式下:结果可能小于200,比如当前线程A取得c的值为3, ...
- keystone系列二:HTTP协议
一 为何要学习HTTP协议 http协议就是通信的双方共同遵守的标准,就好比要合伙办事的两家公司签署的合同. openstack中各组件是基于restful api通信的,restful api可以单 ...
- 给大家推荐8个SpringBoot精选项目
前言 2017年,曾在自己的博客中写下这样一段话:有一种力量无人能抵挡,它永不言败生来倔强.有一种理想照亮了迷茫,在那写满荣耀的地方. 如今2018年已过大半,虽然没有大理想抱负,但是却有自己的小计划 ...
- 探讨.NET Core中实现AES加密和解密以及.NET Core为我们提供了什么方便!
前言 对于数据加密和解密每次我都是从网上拷贝一份,无需有太多了解,由于在.net core中对加密和解密目前全部是统一了接口,只是做具体的实现,由于遇到过问题,所以将打算基本了解下其原理,知其然足矣, ...
- 图解HTTP,TCP,IP,MAC的关系
入门 用户发了一个HTTP的请求,想要访问我们网站的首页,这个HTTP请求被放在一个TCP报文中,再被放到一个IP数据报中,最终的目的地就是我们的115.39.19.22. 进阶 IP数据报其实是通过 ...
- ML.NET 示例:推荐之场感知分解机
写在前面 准备近期将微软的machinelearning-samples翻译成中文,水平有限,如有错漏,请大家多多指正. 如果有朋友对此感兴趣,可以加入我:https://github.com/fei ...
- Codeforces Round #486 (Div. 3)-B. Substrings Sort
B. Substrings Sort time limit per test 1 second memory limit per test 256 megabytes input standard i ...
- Python入门-三级菜单
作业题目: 三级菜单 作业需求: menu = { '北京':{ '海淀':{ '五道口':{ 'soho':{}, '网易':{}, 'google':{} }, '中关村':{ '爱奇艺':{}, ...
- [2017BUAA软工助教]团队alpha得分总表
一.累计得分 项目 介绍 采访 贡献分 功能 技术 α例会 α发布 α测试 α展示 α事后 合计 满分 10 10 10 10 10 50 10 10 150 10 280 hotcode5 10 9 ...
- PAT L3-010 是否完全二叉搜索树
https://pintia.cn/problem-sets/994805046380707840/problems/994805049870368768 将一系列给定数字顺序插入一个初始为空的二叉搜 ...