Home  >  Article  >  Web Front-end  >  利用handlebars实现后端组件化_html/css_WEB-ITnose

利用handlebars实现后端组件化_html/css_WEB-ITnose

WBOY
WBOYOriginal
2016-06-21 08:50:191131browse

似乎掌握了后端组件化的奥义^_^

基本说明(使用过exress和handlebars的可以略过):express中的handlebars引擎是这么生成页面的:

/* layout.hbs * 主模板,所有的的页面都将替换"{{{body}}}","{{}}"相当于占位符,由数据进行替换 */<!DOCTYPE html><html> <head> <title>{{title}}</title> </head> <body> {{{body}}} </body></html>/* index.hbs * 单个页面模板,这里以首页为例。"{{>}}"表示引用其他模板来替换,这里引用名为"partial"的模板 */<div>index</div>{{>partial}}/* partial.hbs * 一个分页文件,被其他模板引用,分页之间也可以互相引用。 */<div>123</div>/* index.html * 当浏览器请求index.html时,经过handlebars模板引擎处理后生成的页面 */ <!DOCTYPE html> <html> <head> <title></title> </head> <body> <div>index</div> <div>123</div> </body> </html>

实现步骤1:模板

react的火热让“组件化”的概念持续升温,不过组件化确实在开发中提供了高可复用的代码,大大减少了工作量和bug,确实值得提倡。举个例子。

<ul class="titles border" id="navigator">  <li class="title">标题1</li>  <li class="title">标题2</li>  <li class="title">标题3</li></ul>

这一段html代码,会在几个页面用到,如果按照一般的做法把这段代码ctrl-c、ctrl-v到要用的页面。就会出现两个问题:1.重复代码增多(ctrl-c、ctrl-v应该是程序员的大忌),当然这不是最重要的,最重要的是第2点——维护性差。如果现在我要把“标题1”改成“标题0”,那么只能进行全量搜索然后替换,不仅操作麻烦而且容易出错。

如果用到了模板技术的话这个问题就很好解决,把上面那一段代码写成一个模板,在handlebars中我们成为分页,然后需要这段的代码的页面引用这个分页,如果要修改的话直接修改分页了。以handlebars为例:

//navigator.hbs<ul class="titles border" id="navigator">  <li class="title">标题1</li>  <li class="title">标题2</li>  <li class="title">标题3</li></ul>//在index.hbs中引用{{>navigator}}

为什么handlebars?本文所用的后端模板引擎都以handlebars为例,原因是上次听去哪儿前端团队做的关于node.js的技术分享,炫耀了一个自己基于handlebars实现的小功能:分页中引用的css文件可以全部放到head中。心中一直觊觎这个小功能,直到最近和“组件化”的概念结合在一起考虑,发现这个功能对于实现后端的组件化很有帮助。自己对handlebars也略有研究,所以试着用handlebars来实现一下“组件化”。

实现步骤2:打包

这样就完美了么?no~no~no~上面的这一段html代码中可是有样式的,按照w3c的规范,样式应该写在css文件中,怎么实现?自然而然想到两种解决办法:

  1. 在分页中加入link标签来引入所需的样式,想一想html代码中到处穿插link标签是什么感觉~且不说生成页面难以维护,浏览器渲染速度也会受影响。
  2. 把分页所需的样式放在公共的样式文件中,这是目前我们项目的通用做法,纯粹的懒人策略,缺点很明显,很多页面引用了一些无用的样式,浪费网络带宽,尤其当项目变大时这个缺点将更加明显。 所以最好的解决方法是按需加载,只加载引用组件所需的样式,当然样式文件按分页拆分得这么细的话会增加请求数,影响不会太大,如果想优化的话也可以压缩合并成一个请求,这个后面再说。 handlerbas中常见的扩展方式就是编写helper,我们可以编写一个helper,

//app.jshbs.registerHelper('css', function(str, option) {  //在上下文中创建一个数组用来保存该页面需要用到的css文件  this.cssList = this.cssList || [];    this.cssList.push(str);});

这个helper的作用就是注册一个名为”css”的helper,帮我们保存分页中用到的css文件地址。然后我们在主模板layout的head标签部分遍历cssList数组循环加载出来。

//layout.hbs<head> <title>{{title}}</title> {{#each cssList}} <link rel="stylesheet" href="{{this}}" media="screen" title="no title" charset="utf-8"> {{/each}}</head>...

同时原来的分页改成

//navigator.hbs{{css '/stylesheets/components/navigator.css'}}<ul class="titles border" id="navigator"> <li class="title">标题1</li> <li class="title">标题2</li> <li class="title">标题3</li></ul>

上面写的只是一个简单的无逻辑的静态组件,有些组件可能会有交互效果,比如处理一些点击事件或者对外暴露可操作的接口等,那么就需要js逻辑来实现了。

实现步骤3:逻辑

其实实现原理也大同小异,也是先注册一个helper,然后在主模板layout中添加,这里我们在原来的分页中引入一个js文件。具体代码如下:

//app.jshbs.registerHelper('js', function(str, option) {  this.jsList = this.jsList || [];  this.jsList.push(str);});

//layout.hbs...<body> {{{body}}} {{#each jsList}} <script src="{{this}}" charset="utf-8"></script> {{/each}}</body>

//navigator.hbs{{css '/stylesheets/components/navigator.css'}}{{js '/javascripts/components/navigator.js'}}<ul class="titles border" id="navigator"> <li class="title">标题1</li> <li class="title">标题2</li> <li class="title">标题3</li></ul>

现在已经实现将css、js、html封装成独立的组件了,不过这样还是有个问题。如果a组件引用了public.css和a.css文件,而b组件引用了public.css和b.css文件,那么按照上面的做法,会在head写两个同样的link标签,组件共同依赖的文件越多,重复的标签就越多。这当然不是我们所想看到的。

实现步骤4:依赖

为了解决这个问题我们还需要去重复,对刚才的两个helper改造一下即可。

//app.jshbs.registerHelper('css', function(str, option) {  var cssList = this.cssList || [];  if(cssList.indexOf(str)<0) {    cssList.push(str);  }  this.cssList = cssList.concat();});hbs.registerHelper('js', function(str, option) {  var jsList = this.jsList || [];  if(jsList.indexOf(str)<0) {    jsList.push(str);  }  this.jsList = jsList.concat();});

最终生成的页面截图:

实现步骤5:合并

最后一步优化。为了减少请求,可以将不同组件所需的资源文件进行合并。这里推荐一个插件 loader 。

示例代码下载地址

以上就是关于后端利用模板实现组件化的探索,实现上虽无问题,但是由于目前没有新的项目,无法在实际项目中使用,所以不知道会不会带来其它的“坑”。欢迎有兴趣的朋友使用后与我交流~

博客: http://yalishizhude.github.io

作者:亚里士朱德

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn