前言

不知不觉间,居然已经这么久没有写博客了,坚持还真是世界上最难的事情啊。

不过我最近也没闲着,辞工换工、恋爱失恋、深圳北京都经历了一番,这有起有落的生活实在是太刺激了,就如拿着两把菜刀剁洋葱一样,想想就泪流满面。

弃我去者、昨日之日不可留,乱我心者、今日之日多烦忧,还是说说最近接触到的模板引擎 Handlebars 吧。

Handlebars 简介

先引用下百科的说法:

Handlebars 是 JavaScript 一个语义模板库,通过对view和data的分离来快速构建Web模板。它采用"Logic-less template"(无逻辑模版)的思路,在加载时被预编译,而不是到了客户端执行到代码时再去编译, 这样可以保证模板加载和运行的速度。

好吧,看了有点懵闭。这里关键词就是两个:无逻辑、预加载。所有的模板引擎都是view和data分离,这点不用说。无逻辑准确点来说应该是弱逻辑,毕竟里面还是有一些if、each逻辑在的。你可能看过很多这样写的模板语言:

1

2

3

4

5

6

7

注:闭合的大括号一定不要忘了写哦。

看这种 js 与 HTML 的杂交写法我觉得很眼疼,我的眼里代码的可读性是非常重要的,这种写法真不是我的那杯茶!不过这种模板技术的实现方式倒是值得一探,推荐看看这个20行代码的模板引擎实现:http://blog.jobbole.com/56689/,挺有意思的做法,当然用eval也可以做。

而 Handlebar 的语法就简单精练了许多,比如上面的可以写成:

1 {{#if names.length}}2

3 {{#each names}}4

{{this}}

5 {{/each}}6

7 {{/if}}

就喜欢这种一目了然的感觉,当然还有其他的swig、tx出的art-template之类的模板引擎,萝卜青菜各有所爱,就不多说了。

语法基础

语法很简单,就是用大括号将 data 包裹起来。其中两个 {{}} 会将内容做HTML编码转换,这里你输入的HTML标签代码什么的都会按你输入的字符输出;而三个 {{{}}} 的时候则不做转换,你在里面输入

最后是真的能得到一个h1标签的。其他一些规则要素分别有:

1)块级

在 Handlebars里面,每个#就代表了一个局部块,每个块都有自身的作用域范围。举例来说:

1 //数据

2 hehe: { words: 'hehehehe'}3 yoyo: { words: 'yoyoyoyo'}

对应的模板:

1 {{#hehe}}2

{{words}}

3 {{/hehe}}4 {{#yoyo}}5

{{words}}

6 {{/yoyo}}

这个例子很好理解,words属性都是根据自身的对象来输出的。这里还是按照块级作用域去理解会比较简单(虽然js并没有块级作用域。。。),也可以用this来指代当前对象。注意,即使是#if、#each也是有作用域的,不要跟js中的作用范围混为一谈。

2)路径

对于对象来说,你可以按照上文的例子一样直接使用 name 的 length 属性,还可以使用使用路径的表达方式去访问对象的其他层级。举个栗子:

1 var post ={2 title: "Blog Post!",3 author: [{4 id: 47,5 name: "Jack"

6 },{7 id: 20,8 name: "Mark"

9 }]10 };

模板要这么写:

1 {{#post}}2 {{#if author.length}}3

{{title}}

4

5 {{#each author}}6

{{../title}}'s author is {{name}}

7 {{/each}}8

9 {{/if}}10 {{/post}}

li标签里面已经是在 author 字段之内了,所以要使用 '../' 来转到上层的 title。

3)helper

上面其实已经用过helper了,内置的helper有if、each、unless、with等,当然你也可以自己去写helper。由于Handlebar的弱逻辑属性,如果要实现复杂一点的逻辑就需要去自定义helper。举个栗子:

1 //判断是否是偶数

2 Handlebars.registerHelper('if_even', function(value, options) {3 console.log('value:', value); //value: 2

4 console.log('this:', this); //this: Object {num: 2}

5 console.log('fn(this):', options.fn(this)); //fn(this): 2是偶数

6 if((value % 2) == 0) {7 return options.fn(this);8 } else{9 return options.inverse(this);10 }11 });

helper是这样用的:

1 {{#if_even num}}2 {{this.num}}是偶数3 {{else}}4 {{this.num}}是奇数5 {{/if_even}}

当然输出你也能想到,就是根据奇数偶数输出相应信息。我们看看定义的一个function(value, options){},这个items就是我们使用模板时候的num,options是一些配置项,这里我们用到的是fn函数,这个函数执行的结果就是编译的结果(这里结果是“2是偶数”这一句话)。另外一个options.inverse就是取反,对应的就是模板里面的else语句了。

but:在模板中过度使用逻辑,实际上就是模糊了模板的专注点,这有违原本数据和表现分离的出发点。我还是认为模板应该专注数据绑定,逻辑应该在数据层做预处理,然后将结果返回给模板,而不是让模板去做各种数据的运算。

4)partial

使用模板引擎最重要的一点就是使用其partial功能,Handlebars里面是按照注册再使用的方式来管理partial的。举个栗子:

1 Handlebars.registerPartial('userMessage',2 'By {{author.firstName}} {{author.lastName}}{{tagName}}>'

3 + '

{{body}}

'

4 );

使用的时候就可以直接使用{{> userMessage}}将这个小块引入到页面中了。这里就是简单的局部替换,所以partial里面的data跟当前页面的data是在同一级的作用域内,也就是说你只要定义好author、body传进去就行了。tagName这个属于表现层的变量,应该在hbs文件里面进行声明,也即是{{> userMessage tagName="h1" }}这样使用。

在前端使用hbs

直接引入js的方式就不多说了,这里我是使用webpack来统一管理各种资源的。Handlebars对应的webpack插件为handlebars-loader,loader的配置非常简单:

1 {2 test: /\.hbs$/,3 loader: "handlebars"

4 }

Handlebars的后缀有两种,全称的handlebars以及简称的hbs,也可以直接用html,但还是跟普通html文件区分开来好一点。

使用模板的好处当然就是可以组件化开发了。我这里采用的目录是这样的:

其中页面组件指的是应用中的页面单元,页面是由各种控件组件组成的,这些都已经是共识了,就不再赘述了。引用的方法有几种:

(1)因为Handlebar编译出来的只是一个字符串,所以我们可以用js作为入口去管理组件,每个组件的js文件引入相应的css和模板,输出为dom字符串。页面引用组件的时候就直接引用js模块得到dom字符串,然后将dom字符串渲染到相应的{{{}}}中去。这种js大一统的方式跟现在主流框架的做法是一样的,可以将逻辑、样式、内容和资源统一起来管理,组件也得内聚性比较强。

1 //header.js

2 require('./header.scss');3 var headerTpl = require('./header.hbs');4 var data = {words: "This is header!"}; //data可以用参数传入5 var header =headerTpl(data);6 module.exports =header;7

8 //home.hbs

9

10 {{{ header }}}11

This is {{name}} page.

12 {{{ footer }}}13

14

15 //home.js

16 require('./home.scss');17 var header = require('../../component/header/header.js');18 var footer = require('../../component/footer/footer.js');19 var homeTpl = require('./home.hbs');20 var data ={21 header: header,22 footer: footer,23 name: 'home'

24 };25 var home =homeTpl(data);26 module.exports = home;

(2) 另外的方案就是使用局部模板的方式了,这种方式对一些不带js逻辑的组件非常合适,比如页头页尾这些纯内容的组件。在hbs里面可以直接按照路径去引用particle,然后把引入组件的时候提供partial所需的数据,例如home页面就是这样的:

{{> ../../component/header/header}}

this is {{}} page

{{> ../../component/footer/footer}}

既然我们已经用了webpack来管理,当然也可以让webpack来处理引用路径了,这里只需要在配置里面声明partial的路径即可直接引用,loader配置:

1 {

2 test: /\.hbs$/,

3 loader: "handlebars",

4 query: {

5 partialDirs: [

6 path.join(SRC_PATH, 'component', 'header'),

7 path.join(SRC_PATH, 'component', 'footer'),

8 path.join(SRC_PATH, 'page', 'home')

9 ]

10 }

11 }

模板文件:

{{> header }}

This is {{name}} page.

{{> footer }}

上面列出的几种方式各有优劣,使用partial的方式可以将相应的模板文件集中放到一个view文件夹里面,partialDirs就不用写一大堆路径了。个人还是更偏向于使用第一种方式,每个组件的css、html、js文件做成一个整体的方式,遵循就近管理原则。

Nodejs后端使用hbs

Node后端使用hbs也非常方便,这里我用的是express框架,直接后端渲染。当然更精细的做法就是首屏渲染、仅移动端后端渲染了,在这种混搭的场合模板是可以通用的,这样就减少了一定的开发工作量。目前express中自带4种模板引擎,jade、esj、hogan与hbs,我是使用express-generator来生成项目脚手架的,输入命令为: express --hbs 项目名。

express-generator中的hbs用的是hbs库(https://github.com/donpark/hbs),而并非很多资料介绍的express-handlebars。hbs默认使用layout模板,实际上就是将你的模板文件替换掉{{{body}}}。layout是可配置的,可以在渲染选项中通过layout项来配置。

1 res.render('index', {2 title: 'Express',3 head: '

head part

',4 layout: true //默认为true,设为false则不启用layout模板

5 });

目前我所接触到的hbs项目都是express+hbs+zepto/jq这一套,如果有用其他前端框架的话,一般也不会用到hbs了,所以只说说这种情况。后端渲染跟前端渲染的开发模式略有差异,但思路还是一样的要做组件化开发。上文说过前端使用hbs的时候是以js为入口,而在后端使用hbs的话个人认为更适合使用局部模板的方式。

我的目录是这样的:

页面统一放入views中,局部模板放入views/partial里面。js和css还是按照官方默认的方式集中管理。使用局部模板要先注册,需要在app.js这个服务器脚本里面加入以下代码:

1 var hbs = require('hbs');2 hbs.registerPartials(__dirname + '/views/partials');

模板文件中引入小模板:

1

2

3

4

{{title}}

5

6

7 {{> resource}}8

9

10 {{> header}}11

12 {{{body}}}13

java handlebars_Handlebars 模板引擎之前后端用法相关推荐

  1. Java开源模板引擎

    Velocity Velocity是一个基于java的模板引擎(template engine).它允许任何人仅仅简单的使用模板语言(template language)来引用由java代码定义的对象 ...

  2. java velocity是什么意思_基于 Java 的模板引擎Velocity快速入门

    最近使用Velocity模板引擎,写一个maven项目Coding生成工具. 对基于Java的模板引擎Velocity的demo总结如下: Step1. 创建Maven项目,添加如下velocity的 ...

  3. java h5模板引擎_详解SpringBoot+Thymeleaf 基于HTML5的现代模板引擎

    序言: Thymeleaf 是Java服务端的模板引擎,与传统的JSP不同,前者可以使用浏览器直接打开,因为可以忽略掉拓展属性,相当于打开原生页面,给前端人员也带来一定的便利.如果你已经厌倦了JSP+ ...

  4. Java Word模板引擎-Poi-tl

    本文内容从Poi-tl官方文档摘录,poi-tl是一个基于Java POI的Word模板引擎,有着非常强大的功能 此处只摘录了一些我现在需要用到的功能 文章目录 一.简单示例 1.准备一个模板文档 ` ...

  5. Twig模板引擎常用基础用法总结

    Twig是一种PHP模板引擎,最近,由于比较频繁的使用Twig模板,于是想总结一下一些常用的基本用法,希望能给对Twig还不熟悉的朋友带来帮助. 首先贴一下Twig官方文档链接:Twig模板语法官方文 ...

  6. Java 基础系列(十六) --- Java中模板引擎的使用

    模板引擎 1 关于动态页面的渲染 2 非模板引擎的弊端 3 模板引擎 3.1 什么是模板引擎? 3.2 Thymeleaf 语法 3.3 模板引擎的使用 4 总结 1 关于动态页面的渲染   渲染就是 ...

  7. java beetl模板引擎_Spring Boot集成beetl模板引擎 个人总结

    1. Spring boot快速集成beetl模板引擎 查看官方文档:http://ibeetl.com/guide/#beetl 可参看官方文档 4.6. Spring Boot集成 增加beetl ...

  8. thymeleaf 调用java,thymeleaf模板引擎调用java类中的方法(附源码)

    前言 由于开源了项目的缘故,很多使用了My Blog项目的朋友遇到问题也都会联系我去解决,有的是把问题留在项目的issue里提出,有的是在我的私人博客里留言,还有的则是直接添加我的qq来找我讲自己遇到 ...

  9. html中模板引擎—前端与后端

    模板引擎 模板引擎 起到 数据和视图分离的作用, 模板对应视图, 关注如何展示数据, 在模板外头准备的数据, 关注那些数据可以被展示. 后端模板引擎 freemarker 如下介绍,  java后台的 ...

最新文章

  1. Apache启用mod_expires模块
  2. 【java的多态性】
  3. JS给html控件赋值
  4. 利用MySQL创建一个简单的employee员工表并修改表
  5. python的inspect模块
  6. html之属性的应用
  7. 真正厉害的产品经理,都是“数据思维”的高手
  8. [转]动态添加Fragments
  9. java 去除jsonarray里面jsonarray的重复和合并数据
  10. viewflipper_Android ViewFlipper示例教程
  11. FreeBSD tips
  12. List集合去重的常见几种方式
  13. 华为ENSP的Stelnet、直连、串口连接、telnet连接登录
  14. 第39级台阶 蓝桥杯
  15. AD软件出现“Your license is already used on computer “LAPTOP-F99R6OR1“ using product “AltiumDesigner“
  16. 基于Android的校园跳蚤市场(二手)的设计与实现(新版)
  17. 牛客错题集C++(一)
  18. 【数据挖掘导论】读书笔记 - (1)
  19. Linux Shell脚本:探测同网段主机及对应MAC地址
  20. ACM算法模板总结(分类详细版)

热门文章

  1. 学python的100个单词_200个Python学习单词请收藏
  2. MSIL Emit AOP
  3. MSIL - 简单的代码解析
  4. 软件工程实践总结——积少成多
  5. 2023 世界人工智能大会(WAIC)人才培养论坛成功举办!
  6. PHP多条件模糊查询代码查询,PHP多条件模糊查询
  7. emlogPro实现模板预览功能(包含模板设置数据)
  8. 教资-中学《综合素质》(考前必背大题)
  9. PyQt5桌面应用开发(11):摸鱼也要讲基本法之桌面精灵
  10. 台式机和便携机属于小型计算机吗,计算机的分类方法有多种,按照计算机的性能和用途来分类,台式机和便携机均属于传统的小型计算机。...