An Introduction to Handlebars(Handlebars 简介)

由于作者翻译会加入 自己的理解 以便自己学习和使用, 如果英文好的同学可看下面   如文章中有翻译错误还请留言. 交流并改正. (:

文章来自net|tuts+ 原文地址  请点击

  ======================Enein翻译=========================
 
    如果你发现你的站内信息老是定期的改变, 那么你可以尝试使用 Handlebars , Handlebars 是一个 "template processor" 模板引擎, 它会动态的生成你HTML页面. 省祛你手动更新的时间, 在这篇文章里我将介绍Handlebars, 并教你怎么为你的站点create一个简单的template.
 
Site template
为什么要让你的页面create一个模板, 这里有两个主要的原因:  
            【1】 创建模板可以使你的逻辑代码与view分离, 来接近实现  view/controller 模式.
            【2】 模板使用你的代码变得 清晰、可维护性提高.
这使得你很快就可以更新你的网站. 你不必为Handlebars设置一个站点, 只需要使用一些语法结构 这样你的网站 页面上会没有固定的数据, 下面介绍一些基础.
The Basics
    Handlebars使用template运行Json格式来生成你的页面, 这些template基本上都是HTML和一些占位和一些占位符(它允许你注入数据) 例:
这段代码是告诉用户你已经登陆:
  
  
  1. <h1>Welcome back, {{name}}</h1>
这个 {{name}}  属性是用户名称是动态注入到页面里来的. 这个占位符是使用一种类似Json结构, 这可能是最基本的例子, 但是你将看到的每一个都会基于这个简单的理念. 让我们继续看这个 "数组".
Arrays
    Handlebars中有一些内置的方法可以提供你处理复杂的数据, “ each”只是其中之一, 这个标签是实现一个 iterator 来实现动态create页面. For example: 
  
  
  1. <table>
  2. <tr>
  3.   <th>Local Concerts</th>
  4. </tr>
  5.   {{#each Concerts}}
  6. <tr>
  7.   <td>{{this}}</td>
  8. </tr>
  9.   {{/each}}
  10. </table>
    你能看到, 这段代码比常规的代码要清晰很多, 类似使用 PHP的loop/Javascript的动态append页面. Handlebars的语法不具有 "intrusive"干扰性, 所以它是很容易理解的.  你可能不会注意到  {{this}} 意思是取出loop中当前的 element。
    这个例子, 实现数组里有简单的值还是很好的, 但是如何处理更复杂的数据? 好吧, 你基本上是做同样的事情,  例如, 我们按照下面的数据,将写一个template
  
  
  1. [
  2. {
  3. Name : "Band",
  4. Date : "Aug 14th, 2012",
  5. Albums : [
  6. {
  7. Name : "Generic Name"
  8. },
  9. {
  10. Name : "Something Else!!"
  11. }
  12. ]
  13. },
  14. {
  15. Name : "Other Guys",
  16. Date : "Aug 22nd, 2012"
  17. Albums : [
  18. {
  19. Name : "Album One"
  20. }
  21. ]
  22. }
  23. ]
我们很容易使用下面的template来实现上面的数据显示:
 
 
  1. <table>
  2. <tr>
  3.   <th>Band Name</th>
  4.   <th>Date</th>
  5.   <th>Album Name</th>
  6. </tr>
  7. {{#each Bands}}
  8. <tr>
  9.   <td>{{Name}}</td>
  10.   <td>{{Date}}</td>
  11.   <td>{{Albums.0.Name}}</td>
  12. </tr>
  13. {{/each}}
  14. </table>

    在Handlebars中, 你甚至能访问内嵌属性, like in (Albums.0.Name). 当然你也可再使用一个each来loop你的数组. 你应该注意到了, 上面的例子中使用的 . 来访问属性, 你也能使用 ../ 来访问 父级的属性.

    如果数组为空没有任何数据, 你当然不希望有一个空的 table, Handlebars 很友好的提供了  if else 和  unless 语法, 这个  if ... else 在一些程序语言中都工作的很好, 如果这个Object是 false或是假类型, 然后 else 将执行. 相反,   if 代码块将会执行.  这个 unless是非常有意思的; 它是一个相反的 if代码块, 如查表达式为 true, 这个unless块不执行. 所以让我们来加入这个方法.
  
  
  1. {{#if Bands}}
  2. <table>
  3.   <tr>
  4.     <th>Band Name</th>
  5.     <th>Date</th>
  6.     <th>Album Name</th>
  7.   </tr>
  8.   {{#each Bands}}
  9.   <tr>
  10.     <td>{{Name}}</td>
  11.     <td>{{Date}}</td>
  12.   <td>{{Albums.0.Name}}</td>
  13.   </tr>
  14.   {{/each}}
  15. </table>
  16.   {{else}}
  17.   <h3>There are no concerts coming up.</h3>
  18. {{/if}}
Custom Helpers
Handlebars 可以提供给你自定义这个json语法的能力. 在Handlebars里只是简单的注册一下你的Function, 然后一些template在编译的时候就可以使用你的语法. 下面的有两种类型可以让你去创建:
 
    • Function helpers 是基本的Function函数, 注册一次, 就可以在Handlebars template中的任何地方使用. Handlebars会写这个Function的回值到template上.
    • Block helpers 是类似 if , each, etc 它们允许人改变 上面文里的
  • 让我展示给你一个简单的例子. 首先, 我将会注册一个function helper 通过以下代码:
  •     
        
    1. Handlebars.registerHelper("Max", function(A, B){
    2. return (A > B) ? A : B;
    3. });
    这个 registerHelper的第一个参数是这个 helper 的名子, 我将会在template里使用它. 这个第二个参数, 是一个匿名函数.
  • 如何使用请看下面的例子:
  •     
        
    1. {{Max 12 45}}
    这个template 使用 Max 语法 , 和解析 12 和 45 到这个函数里, Handlebars 函数 helper里支持多个参数, 你可以直接插入数据 到template本身, 或者你能使用Json结构的属性.
    现在让我们看一下Block helper, Block helper, 允许你在代码运行前设置这个context, 例如下面这个Object:
  
  
  1. {
  2. Name: "Parent",
  3. Sub: {
  4. Name: "Child"
  5. }
  6. }
这里有两个key相同的Name属性, 与一个Helper来实现 即可以调用父级的Name, 又可以调用 child的Name:
  
  
  1. Handlebars.registerHelper("BothNames", function(context, options){
  2. return options.fn(context) + options.fn(context.Sub);
  3. });
template看起来像这样:
 
 
  1. {{#BothNames this}}
  2.   <h2>{{Name}}</h2>
  3. {{/BothName}}

这个结束的语法名称 是告诉Handlebars这是一个block helper,和关闭它。

这个 options.fn 函数运行模板内部的块. 你可以把context传给它.
现在基础已经告一段落, 让我们来一个完整的Demo吧.
Building a Site Template
我们将使用template来构建一个食谱网站. 这将将会让你这将会让你很好的明白, Handlebars通过API取得数据和在模板中如何解析.
 
Setting up a Handlebars project
 
我们必须首先加载我们的 template script, 但为了做到这一点, 我们需要创建一个HTML文件和包含我们的Handlebars.js文件
 
 
  1. <html>
  2.   <head>      
  3.     <title>Handlebars Demo</title>    
  4.     <script type="text/javascript" src="Handlebars.js"></script>   
  5.   </head>  
  6.   <body>    
  7.     <script id="Handlebars-Template" type="text/x-handlebars-template"></script>   
  8.   </body>
  9. </html>
    为了简单, 你能存储你的template到<script>里和加载它通过JavaScript.这比它直接存储到JavaScript里一个变量干净多了.
现在让我们讨论这个app如何工作. 首先使这个app连接一个API去取到一些食谱信息. 下一步, 我们通过把这些信息放到Handlebars和通过template运行它. 最后, 我们通过新生成的页面把body里的内容替换掉, 它是一个相当直接的一个过程; 所以, 让我们开始在</body>之前加入第二个script代码块来初始化Ajax变量.
 
 
  1. <script>
  2. var Ajax = (window.XMLHttpRequest) ? new XMLHttpRequest() : new ActiveXObject("Microsoft.XMLHTTP");
  3. Ajax.onreadystatechange = function () {  
  4.  if (Ajax.readyState == 4 && Ajax.status == 200) {     
  5.   //Parse the JSON data     
  6.   var RecipeData = JSON.parse(Ajax.responseText);      
  7.   //Get the Template from above     
  8.   var Source = document.getElementById("Handlebars-Template").textContent;     
  9.   //Compile the actual Template file      
  10.   var Template = Handlebars.compile(Source);      //Generate some HTML code from the compiled Template    
  11.   var HTML = Template({ Recipes : RecipeData });      //Replace the body section with the new code.    
  12.   document.body.innerHTML = HTML;   
  13. }}
  14.  
  15. Ajax.open("GET","Recipe.php", true);
  16. Ajax.send();
  17. </script>

这是通过一个template去动态的编译生成html。 理论上你可以直接把Json数据放到Handlebars中, 但是你运行时会出现跨域问题。 代替的方法是使用PHP里的echo把它变为一个JavaScript的变量.所以在运行这个模板之前我会将所以的操作分到"Recipe.php"里去做. 让我们看一下这个PHP文件。

 
 Geting The Date
这个Yummly API 是相当简单, 没有身份验证系统; 你只需要注册, 取得验证信息加入到URL中,如果你想你可以通过 echo 来处理这些数据.
但我想要更详细的信息为每一个食谱, 在这之前, 我调用两个请求.
  
  
  1. matches;
  2. //Cycle Through The Recipes and Get full recipe for each
  3. foreach($Recipes as $Recipe)
  4. {
  5. $ID = $Recipe->id;
  6. $R = json_decode(file_get_contents("http://api.yummly.com/v1/api/recipe/" . $ID . "?_app_id=" . $UserID . "&_app_key=" . $UserKey . "&images=large"));
  7. //This is the data we are going to pass to our Template
  8. array_push($Json, array(
  9. Name => $R->name,
  10. Ingredients => $R->ingredientLines,
  11. Image => $R->images[0]->hostedLargeUrl,
  12. Yield => $R->yield,
  13. Flavors => $R->flavors,
  14. Source => array(
  15. Name => $R->source->sourceDisplayName,
  16. Url => $R->source->sourceRecipeUrl
  17. )
  18. ));
  19. }
  20. //Print out the final JSON object
  21. echo json_encode($Json);
  22. ?>
下面是Handlebars template 程序, 你只需要几行代码就可以生成一个完整的网站.
  
  
  1. <script id="Handlebars-Template" type="text/x-handlebars-template">  
  2.  <div id="Content">    
  3.   <h1>&Xi;RecipeCards    
  4.     <span id='BOS'>Recipe search powered by        
  5.       <a id='Logo' href='http://www.yummly.com/recipes'>           
  6.         <img src='http://static.yummly.com/api-logo.png'/>       
  7.       </a>     
  8.     </span>    
  9.   </h1>
  10.   {{#each Recipes}}     
  11.   <div class='Box'>        
  12.     <img class='Thumb' src="{{{Image}}}" alt="{{Name}}">     
  13.     <h3>{{Name}} <a id='Logo' href="{{Source.Url}}"> - {{Source.Name}}</a></h3>     
  14.     <h5>{{getFlavor Flavors}}</h5>       
  15.     <h5>{{Yield}}</h5>         
  16.     <p>Ingredients:</p>      
  17.     <ul>          
  18.       {{#each Ingredients}}           
  19.       <li>{{this}}</li>        
  20.       {{/each}}        
  21.     </ul>    
  22.   </div>
  23.     {{/each}}  
  24. </div>
  25. </script>
让我们运行这段代码.  第6行只是一个Logo然后, 然后列出所有的食谱, 我们创建一个食谱卡片通过一个图片, 一个名称和一个配料.
这个Yummly API 返回味道数据. 我写一个 Function helper, 叫 getFlavor 取出味道数据到一个盘子里.为了使这个模板进行工作, 在解析template之前我们需要加载 getFlavor , 所以在Ajax Code 之前加入.
 
 
  1. Handlebars.registerHelper("getFlavor", function(FlavorsArr){
  2. var H = 0;
  3. var Name = '';
  4. for(var F in FlavorsArr)
  5. {
  6. if(FlavorsArr[F] > H)
  7. {
  8. H = FlavorsArr[F];
  9. Name = F;
  10. }
  11. }
  12. return "This Dish has a " + Name + " Flavor";
  13. });
现在, 当Handlebars解析到 getFlavor 时, 它调用相关功能和检索出味道信息.
在这点上, 你可以自由的设计你的模板. 但是你可能看到这个过程是很缓慢的. 这主要是由于这个三个请求调用是在 Handlerbars template加载之前的.显然这不是一个好的办法. 但precompiling你的template会有所帮助
 
Precompiling
你有两个不同的操作, 这第一个是预编译template, 这是为了降低加载时间, 和你将要包涵一个Handlebars compiler 到你的页面
我们的问题是 浏览器与API通信问题, 如果你想要预处理你的template, 你可以下载Node.js包 通过 npm 下面命令:
   
   
  1. npm install handlebars -g
你可能需要 root 权限, 安装完成, 你能为你的template创建一个文件和编译它像这样
  
  
  1. handlebars demo.handlebars -f demo.js
你可以给你的template文件一个“.handlebars”扩展名. 这不是强制的, 如果你的名称是类似 demo.html, 然后你的template文件名称是将会是"demo.html"有用部分仅仅是"demo",命名你的template后, 运行Handlebars后将内容输出到文件中,使用如下
  
  
  1. var template = Handlebars.templates['demo'];
  2. var html = template({ Your Json Data Here });
但是, 正如我前面所说的, 这并没有帮助我们解决问题. 我们该怎么做? 好吧, 我们能precompile和输出实体文件. 这使我们可以运行最终html的模板数据 --- 换句话说也就是 caching。
 
不幸的是. 在客户端Javascript没有文件IO功能。 所以容易做到的方法就是输出html后手动保存它. 利用API' caching ! 并确保在保存静态页面时先取得数据.
 
附录

[1] Yummly:   Yummly 是一个语义食谱搜索引擎,拥有50多万份食谱,用户可以根据口味、原料、价格、营养等搜索到所需要的食品。Yummly会根据用户过去的搜索,不断学习喜好,从而推荐可能会感兴趣的食品给你。

[2] Helper:     文章里使用的helper 是指Handlebars里有一个语法。

 
======================Enein翻译=========================
由于作者翻译会加入 自己的理解 以便自己学习和使用. 如有转载请注明出处谢谢.  如文章中有翻译错误或有更好的方案还请留言. 交流并改正
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值