最近几天折腾了下express,想找个合适的模版引擎,下面是一些折腾过程的备忘

选择标准

选择一门模版语言时,可能会考虑的几点

  • 语法友好(micro tmpl那种语法真是够了)
  • 支持模版嵌套(子模版的概念)
  • 支持模版继承(extend)
  • 前后端共用
  • 有容错处理(最好定位到具体出错位置)
  • 支持预编译(性能好)

注意到hbs,似乎满足大部分的需求:https://github.com/donpark/hbs

getting started

demo地址:https://github.com/chyingp/blog/tree/master/demo/2015.04.01-hbs/getting-started 
目录结构如下:

.
├── app.js
├── node_modules
│ ├── express
│ └── hbs
├── package.json
└── views
└── index.hbs

看下app.js内容,还是比较容易理解的。模版views/index.hbs没什么好说的,语法跟handlbars一样

var express = require('express'),
hbs = require('hbs'),
app = express(); app.set('view engine', 'hbs'); // 用hbs作为模版引擎
app.set('views', __dirname + '/views'); // 模版所在路径 app.get('/', function(req, res){
res.render('index', {title: 'hbs demo', author: 'chyingp'});
}); app.listen(3000);

模版继承:layout.hbs

demo地址:https://github.com/chyingp/blog/tree/master/demo/2015.04.01-hbs/inherit-from-layout

如果稍微看过hbs源码可以知道,hbs默认会到views下找layout.hbs这个模版,将这个模板作为基本骨架,来渲染返回的页面。

getting-started里的例子来说,比如用户请求 http://127.0.0.1:3000,那么,处理步骤如下

  1. 查找views/index.hbs,进行编译,并将编译的结果保存为 A
  2. 查找views/layout.hbs,如果 
    1. 存在:对layout.hbs进行编译,其中{{{body}}}标签替换成 A,并返回最终编译结果B
    2. 不存在:返回A

直接看例子。目录机构如下,可以看到多了个layout.hbs

.
├── app.js
├── node_modules
│ ├── express
│ └── hbs
├── package.json
├── public
│ └── style.css
└── views
├── index.hbs
├── layout.hbs
└── profile.hbs

layout.hbs的内容如下:

<!DOCTYPE html>
<html>
<head>
<title>{{title}}</title>
<link rel="stylesheet" type="text/css" href="/style.css">
</head>
<body> {{{body}}} </body>
</html>

相应的,index.hbs调整为

<h1>Demo by {{author}}</h1>

<p>{{author}}: welcome to homepage, I'm handsome!</p>

再次访问 http://127.0.0.1:3000,可以看到返回的页面

模版继承+自定义扩展

demo地址:https://github.com/chyingp/blog/tree/master/demo/2015.04.01-hbs/inherit-and-override

在项目中,我们会有这样的需求。页面的基础骨架是共享的,但某些信息,每个页面可能是不同的,比如引用的css文件、meta标签等。那么,除了上面提到的“继承”之外,还需要引入类似“覆盖”的特性。

hbs官方其实就提供了demohttps://github.com/donpark/hbs/blob/master/examples/extend/ ,感兴趣的同学可以去围观下。可以看到,在app.js里面加入了下面的 helper function`,这就是实现”覆盖“ 的关键代码了。

var blocks = {};

hbs.registerHelper('extend', function(name, context) {
var block = blocks[name];
if (!block) {
block = blocks[name] = [];
} block.push(context.fn(this)); // for older versions of handlebars, use block.push(context(this));
}); hbs.registerHelper('block', function(name) {
var val = (blocks[name] || []).join('\n'); // clear the block
blocks[name] = [];
return val;
});

此外,layout.hbs需要做点小改动。里面比较明显的变化是加入了下面的block标记

{{{block "stylesheets"}}}
 {{{block "scripts"}}}

那么,可以在index.hbs里对这些标记的内容进行覆盖(或者说自定义),包括其他的模版,如果有需要,都可以对这两个`block进行覆盖。

{{#extend "stylesheets"}}
<link rel="stylesheet" href="/css/index.css"/>
{{/extend}} let the magic begin {{#extend "scripts"}}
<script>
document.write('foo bar!');
</script>
{{/extend}}

那么问题来了。如果有这样的需求:所有的页面,都引用 style.css,只有 index.hbs 引用 index.css,那么上面的改动还不足以满足这个需求。

其实,只需要改几行代码就可以实现了,扩展性点个赞。改动后的app.js如下

var blocks = {};

hbs.registerHelper('extend', function(name, context) {
var block = blocks[name];
if (!block) {
block = blocks[name] = [];
} block.push(context.fn(this)); // for older versions of handlebars, use block.push(context(this));
}); // 改动主要在这个方法
hbs.registerHelper('block', function(name, context) {
var len = (blocks[name] || []).length;
var val = (blocks[name] || []).join('\n'); // clear the block
blocks[name] = []; return len ? val : context.fn(this);
});
 
 
 
 

Express模版引擎hbs备忘的更多相关文章

  1. Express学习 ------模版引擎(handlebars)

    Handlebars一款js模版引擎,我们在做客户端开发的时候,也可能已经使用过.它语法比较简单,和我们平常写的html 一样,只不过html 中可以加入handlebars 表达式. handleb ...

  2. Nodejs学习笔记(五)--- Express安装入门与模版引擎ejs

    目录 前言 Express简介和安装 运行第一个基于express框架的Web 模版引擎 ejs express项目结构 express项目分析 app.set(name,value) app.use ...

  3. Express安装入门与模版引擎ejs

    Express安装入门与模版引擎ejs 目录 前言 Express简介和安装 运行第一个基于express框架的Web 模版引擎 ejs express项目结构 express项目分析 app.set ...

  4. Nodejs学习笔记(五)—Express安装入门与模版引擎ejs

    前言 前面也学习了一些Node.js的基本入门知道,现在开始进入Web开发的部分: Node.js提供了http模块,这个模块中提供了一些底层接口,可以直接使用,但是直接开发网站那还是太累了,所以ht ...

  5. 【11】 Express安装入门与模版引擎ejs

    前言 Express简介和安装 运行第一个基于express框架的Web 模版引擎 ejs express项目结构 express项目分析 app.set(name,value) app.use([p ...

  6. AngularJS之备忘与诀窍

    译自:<angularjs> 备忘与诀窍 目前为止,之前的章节已经覆盖了Angular所有功能结构中的大多数,包括指令,服务,控制器,资源以及其它内容.但是我们知道有时候仅仅阅读是不够的. ...

  7. 简单JavaScript模版引擎优化

    在上篇博客最简单的JavaScript模板引擎 说了一下一个最简单的JavaScript模版引擎的原理与实现,作出了一个简陋的版本,今天优化一下,使之能够胜任日常拼接html工作,先把上次写的模版函数 ...

  8. Nmap备忘单:从探索到漏洞利用(Part 5)

    这是备忘单的最后一部分,在这里主要讲述漏洞评估和渗透测试. 数据库审计 列出数据库名称 nmap -sV --script=mysql-databases 192.168.195.130 上图并没有显 ...

  9. Nmap备忘单:从探索到漏洞利用(Part 4)

    这是我们的Nmap备忘单的第四部分(Part 1. Part 2. Part 3).本文中我们将讨论更多东西关于扫描防火墙,IDS / IPS 逃逸,Web服务器渗透测试等.在此之前,我们应该了解一下 ...

随机推荐

  1. 无法获取链接服务器 "XXX" 的 OLE DB 访问接口 "SQLNCLI10" 的架构行集 "DBSCHEMA_TABLES_INFO"。该访问接口支持该接口,但使用该接口时返回了失败代码。

    1. SQL 2000 下载补丁 SQL2KSP4 ,进行安装 2.找到SQL2KSP4\install\instcat.sql 并在sql2000 中打开查询分析器中执行

  2. 正确计算linux系统内存使用率

    参考:https://blog.gesha.net/archives/406/ 图中的例子很典型,就是:多数的linux系统在free命令后会发现free(剩余)的内存很少,而自己又没有开过多的程序或 ...

  3. 加载驱动三种execute

    executeQuery executeUpdate executeQueryBatch

  4. 2-5 R语言基础 factor

    #因子:分类数据#有序和无序#整数向量+标签label#Male/Female#常用于lm(),glm() > x <- factor(c("female"," ...

  5. 死磕nginx系列--nginx 限流配置

    限流算法 令牌桶算法 算法思想是: 令牌以固定速率产生,并缓存到令牌桶中: 令牌桶放满时,多余的令牌被丢弃: 请求要消耗等比例的令牌才能被处理: 令牌不够时,请求被缓存. 漏桶算法 算法思想是: 水( ...

  6. ssh访问服务器端visdom

    在服务器端启动visdompython -m visdom.server在windows端,将服务器的8097端口重定向到windows端(做了映射绑定):ssh -L 8097:127.0.0.1: ...

  7. iOS11 Xcode 9 按住command 单击 恢复到从前(直接跳转到定义)

    iOS11 Xcode 9  按住command 单击 恢复到从前(直接跳转到定义)   2017年9月20日,苹果如期推送 Xcode 9 和 iOS 11的更新. Xcode 9正式版与之前bet ...

  8. mvc 在view视图中直接输出rdlc报表文件(Excel、PDF、Word)

    给一段代码做参考 public ActionResult RdlcReport(string code) { LocalReport localReport = new LocalReport(); ...

  9. Altium 拼板方法以及 注意的 地方

    1.修改软件设置, 即工具→优先选项→覆铜重建 对号去掉,如下,否则 拼板复制 覆铜 会变形导致拼板错误!!! 2.拼板方法,Ctrl+A全部复制(不要漏掉),选择特殊粘贴的方式,快捷键 E→A  去 ...

  10. 【LeeCode88】Merge Sorted Array★

    1.题目描述: 2.解题思路: 题意:两个由整数构成的有序数组nums1和nums2,合并nums2到nums1,使之成为一个有序数组.注意,假设数组nums1有足够的空间存储nums1和nums2的 ...