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和一些占位和一些占位符(它允許你注入數據) 例:
這段代碼是告訴用戶你已經登陸:
<h1>Welcome back, {{name}}</h1>
這個 {{name}}  屬性是用戶名稱是動態注入到頁面里來的. 這個占位符是使用一種類似Json結構, 這可能是最基本的例子, 但是你將看到的每一個都會基於這個簡單的理念. 讓我們繼續看這個 "數組".
Arrays
    Handlebars中有一些內置的方法可以提供你處理復雜的數據, “ each”只是其中之一, 這個標簽是實現一個 iterator 來實現動態create頁面. For example: 
<table>
<tr>
  <th>Local Concerts</th>
</tr>
  {{#each Concerts}}
<tr>
  <td>{{this}}</td>
</tr>
  {{/each}}
</table>
    你能看到, 這段代碼比常規的代碼要清晰很多, 類似使用 PHP的loop/Javascript的動態append頁面. Handlebars的語法不具有 "intrusive"干擾性, 所以它是很容易理解的.  你可能不會注意到  {{this}} 意思是取出loop中當前的 element。
    這個例子, 實現數組里有簡單的值還是很好的, 但是如何處理更復雜的數據? 好吧, 你基本上是做同樣的事情,  例如, 我們按照下面的數據,將寫一個template
[
   {
      Name : "Band",
      Date : "Aug 14th, 2012",
      Albums : [
         {
            Name : "Generic Name"
         },
         {
            Name : "Something Else!!"
         }
      ]
   },
   {
      Name : "Other Guys",
      Date : "Aug 22nd, 2012"
      Albums : [
         {
            Name : "Album One"
         }
      ]
   }
]
我們很容易使用下面的template來實現上面的數據顯示:
<table>
<tr>
  <th>Band Name</th>
  <th>Date</th>
  <th>Album Name</th>
</tr>
{{#each Bands}}
<tr>
  <td>{{Name}}</td>
  <td>{{Date}}</td>
  <td>{{Albums.0.Name}}</td>
</tr>
{{/each}}
<
/table>

    在Handlebars中, 你甚至能訪問內嵌屬性, like in (Albums.0.Name). 當然你也可再使用一個each來loop你的數組. 你應該注意到了, 上面的例子中使用的 . 來訪問屬性, 你也能使用 ../ 來訪問 父級的屬性.

    如果數組為空沒有任何數據, 你當然不希望有一個空的 table, Handlebars 很友好的提供了  if else 和  unless 語法, 這個  if ... else 在一些程序語言中都工作的很好, 如果這個Object是 false或是假類型, 然后 else 將執行. 相反,   if 代碼塊將會執行.  這個 unless是非常有意思的; 它是一個相反的 if代碼塊, 如查表達式為 true, 這個unless塊不執行. 所以讓我們來加入這個方法.
{{#if Bands}}
<table>
  <tr>
    <th>Band Name</th>
    <th>Date</th>
    <th>Album Name</th>
  </tr>
  {{#each Bands}}
  <tr>
    <td>{{Name}}</td>
    <td>{{Date}}</td>
  <td>{{Albums.0.Name}}</td>
  </tr>
  {{/each}}
</table>
  {{else}}
  <h3>There are no concerts coming up.</h3>
{{/if}}
Custom Helpers
Handlebars 可以提供給你自定義這個json語法的能力. 在Handlebars里只是簡單的注冊一下你的Function, 然后一些template在編譯的時候就可以使用你的語法. 下面的有兩種類型可以讓你去創建:
 
    • Function helpers 是基本的Function函數, 注冊一次, 就可以在Handlebars template中的任何地方使用. Handlebars會寫這個Function的回值到template上.
    • Block helpers 是類似 if , each, etc 它們允許人改變 上面文里的
  • 讓我展示給你一個簡單的例子. 首先, 我將會注冊一個function helper 通過以下代碼:
  • Handlebars.registerHelper("Max", function(A, B){
       return (A > B) ? A : B;
    });
    
    這個 registerHelper的第一個參數是這個 helper 的名子, 我將會在template里使用它. 這個第二個參數, 是一個匿名函數.
  • 如何使用請看下面的例子:
  • {{Max 12 45}}
    
    這個template 使用 Max 語法 , 和解析 12 和 45 到這個函數里, Handlebars 函數 helper里支持多個參數, 你可以直接插入數據 到template本身, 或者你能使用Json結構的屬性.
    現在讓我們看一下Block helper, Block helper, 允許你在代碼運行前設置這個context, 例如下面這個Object:
{
   Name: "Parent",
   Sub: {
      Name: "Child"
   }
}
這里有兩個key相同的Name屬性, 與一個Helper來實現 即可以調用父級的Name, 又可以調用 child的Name:
Handlebars.registerHelper("BothNames", function(context, options){
   return options.fn(context) + options.fn(context.Sub);
});
template看起來像這樣:
{{#BothNames this}}
  <h2>{{Name}}</h2>
{{/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文件
<html>
  
<head>      
    <title>Handlebars Demo</title>    
    <script type="text/javascript" src="Handlebars.js"></script>   
  </head>  
  <body>    
    <script id="Handlebars-Template" type="text/x-handlebars-template"></script>   
  </body>
</html>
    為了簡單, 你能存儲你的template到<script>里和加載它通過JavaScript.這比它直接存儲到JavaScript里一個變量干凈多了.
現在讓我們討論這個app如何工作. 首先使這個app連接一個API去取到一些食譜信息. 下一步, 我們通過把這些信息放到Handlebars和通過template運行它. 最后, 我們通過新生成的頁面把body里的內容替換掉, 它是一個相當直接的一個過程; 所以, 讓我們開始在</body>之前加入第二個script代碼塊來初始化Ajax變量.
<script>
var Ajax = (window.XMLHttpRequest) ? new XMLHttpRequest() : new ActiveXObject("Microsoft.XMLHTTP");
Ajax.onreadystatechange = function () {  
 
if (Ajax.readyState == 4 && Ajax.status == 200) {     
  //Parse the JSON data     
  var RecipeData = JSON.parse(Ajax.responseText);      

  //Get the Template from above     
  var Source = document.getElementById("Handlebars-Template").textContent;     
  //Compile the actual Template file      

  var Template = Handlebars.compile(Source);      //Generate some HTML code from the compiled Template    
  var HTML = Template({ Recipes : RecipeData });      //Replace the body section with the new code.    
  document.body.innerHTML = HTML;   
}}

Ajax.open("GET","Recipe.php", true);
Ajax.send();
</script>

這是通過一個template去動態的編譯生成html。 理論上你可以直接把Json數據放到Handlebars中, 但是你運行時會出現跨域問題。 代替的方法是使用PHP里的echo把它變為一個JavaScript的變量.所以在運行這個模板之前我會將所以的操作分到"Recipe.php"里去做. 讓我們看一下這個PHP文件。

 
 Geting The Date
這個Yummly API 是相當簡單, 沒有身份驗證系統; 你只需要注冊, 取得驗證信息加入到URL中,如果你想你可以通過 echo 來處理這些數據.
但我想要更詳細的信息為每一個食譜, 在這之前, 我調用兩個請求.
  
  
  
          matches;
   //Cycle Through The Recipes and Get full recipe for each
   foreach($Recipes as $Recipe)
   {
      $ID = $Recipe->id;
      $R = json_decode(file_get_contents("http://api.yummly.com/v1/api/recipe/" . $ID . "?_app_id=" . $UserID . "&_app_key=" . $UserKey . "&images=large"));
      //This is the data we are going to pass to our Template
      array_push($Json, array(
         Name => $R->name,
         Ingredients => $R->ingredientLines,
         Image => $R->images[0]->hostedLargeUrl,
         Yield => $R->yield,
         Flavors => $R->flavors,
         Source => array(
            Name => $R->source->sourceDisplayName,
            Url => $R->source->sourceRecipeUrl
         )
      ));
   }
   //Print out the final JSON object
   echo json_encode($Json);
?>
下面是Handlebars template 程序, 你只需要幾行代碼就可以生成一個完整的網站.
<script id="Handlebars-Template" type="text/x-handlebars-template">  
 <div id="Content">    
  <h1>&Xi;RecipeCards    
    <span id='BOS'>Recipe search powered by        
      <a id='Logo' href='http://www.yummly.com/recipes'>           
        <img src='http://static.yummly.com/api-logo.png'/>       
      </a>     
    </span>    
  </h1>
  {{#each Recipes}}     
  <div class='Box'>        
    <img class='Thumb' src="{{{Image}}}" alt="{{Name}}">     
    <h3>{{Name}} <a id='Logo' href="{{Source.Url}}"> - {{Source.Name}}</a></h3>     
    <h5>{{getFlavor Flavors}}</h5>       
    <h5>{{Yield}}</h5>         
    <p>Ingredients:</p>      
    <ul>          
      {{#each Ingredients}}           
      <li>{{this}}</li>        
      {{/each}}        
    </ul>    
  </div>
    
{{/each}}  
</div>
</script>
讓我們運行這段代碼.  第6行只是一個Logo然后, 然后列出所有的食譜, 我們創建一個食譜卡片通過一個圖片, 一個名稱和一個配料.
這個Yummly API 返回味道數據. 我寫一個 Function helper, 叫 getFlavor 取出味道數據到一個盤子里.為了使這個模板進行工作, 在解析template之前我們需要加載 getFlavor , 所以在Ajax Code 之前加入.
Handlebars.registerHelper("getFlavor", function(FlavorsArr){
   var H = 0;
   var Name = '';
   for(var F in FlavorsArr)
   {
      if(FlavorsArr[F] > H)
      {
         H = FlavorsArr[F];
         Name = F;
      }
   }
   return "This Dish has a " + Name + " Flavor";
});
現在, 當Handlebars解析到 getFlavor 時, 它調用相關功能和檢索出味道信息.
在這點上, 你可以自由的設計你的模板. 但是你可能看到這個過程是很緩慢的. 這主要是由於這個三個請求調用是在 Handlerbars template加載之前的.顯然這不是一個好的辦法. 但precompiling你的template會有所幫助
 
Precompiling
你有兩個不同的操作, 這第一個是預編譯template, 這是為了降低加載時間, 和你將要包涵一個Handlebars compiler 到你的頁面
我們的問題是 瀏覽器與API通信問題, 如果你想要預處理你的template, 你可以下載Node.js包 通過 npm 下面命令:
npm install handlebars -g
你可能需要 root 權限, 安裝完成, 你能為你的template創建一個文件和編譯它像這樣
handlebars demo.handlebars -f demo.js
你可以給你的template文件一個“.handlebars”擴展名. 這不是強制的, 如果你的名稱是類似 demo.html, 然后你的template文件名稱是將會是"demo.html"有用部分僅僅是"demo",命名你的template后, 運行Handlebars后將內容輸出到文件中,使用如下
var template = Handlebars.templates['demo'];
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翻譯=========================
由於作者翻譯會加入 自己的理解 以便自己學習和使用. 如有轉載請注明出處謝謝.  如文章中有翻譯錯誤或有更好的方案還請留言. 交流並改正. (:


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM