對於java開發,涉及到頁面展現時,比較主流的有兩種解決方案:javascript
1. struts2+vo+el表達式。html
這種方式,重點不在於struts2,而是vo和el表達式,其基本思想是:根據頁面須要的信息,構造出一個實體,這個實體中包含了界面須要的全部屬性,一般這個實體是由N個表中的字段構成的,俗稱vo。因爲vo的屬性能夠是String、List、Map等等等,又能夠vo套vo,所以這種方式很是靈活,也很是好用。java
在後臺對vo進行賦值,經過struts2封裝到request中,而後在界面用el表達式,一般是${}、forEach標籤什麼的,便可構造出界面。jquery
但這種方式小菜卻不是很看好。由於這種利用標籤控制html,依然是把表現和控制混雜在一塊兒,html裏邊混雜了大量el控制標籤,很不美觀。ajax
固然,小菜不可能由於這麼簡單的理由拒絕這種方式,讀者仔細思考能夠發現,利用el表達式生成html代碼,這是一個在服務器端執行的動做,在服務器端解析完成以後,才發送到客戶端瀏覽器上,這樣作會佔用大量服務器資源,並且速度緩慢。json
示例代碼:bootstrap
1 <c:forEach var='bm' items="${contractAuditVo.borrowerModels}"> 2 <table> 3 <tbody> 4 <tr> 5 <td>借款人編號:</td> 6 <td> 7 <p> 8 ${bm.borrowerId } 9 </p> 10 </td> 11 </tr> 12 <tr> 13 <td>客戶編號:</td> 14 <td> 15 <p> 16 ${bm.customerId } 17 </p> 18 </td> 19 </tr> 20 <tr> 21 <td>曾用名:</td> 22 <td> 23 <p> 24 ${bm.usedName } 25 </p> 26 </td> 27 </tr> 28 </tbody> 29 </table> 30 </c:forEach>
2. Json+ajax+拼html。瀏覽器
這種方法通常是基於ajax請求,要求服務器端返回一個json類型的json字符串,這個json串中包含了界面所需的全部信息,界面拿到json串後,構造出html,完成界面展現。服務器
小菜推薦這種方法,經過這種方式編寫的頁面,反應速度很是快,用戶體驗很是好。app
由於服務器端只須要提供一個json串,由客戶端完成解析,所以服務器承受的壓力很小,目前的電腦配置都較高,客戶端的瀏覽器解析js腳本很快,所以頁面體驗效果好。
解析的過程大體是經過Jquery的each方法,進行遍歷。
可是小菜利用這種方式時,犯了一個致命的錯誤,小菜是經過原始的拼接html的方式,頁面中寫了大量html+=」<div>」;,這種寫法使頁面變得很是凌亂,幾乎不能夠維護。
示例代碼:
1 var contractTextHtml=""; 2 $.each(jsonObject.cl,function(i,n){ 3 4 contractTextHtml=""; 5 6 //插入合同文本數據 7 contractTextHtml+="<div title='出借人信息---"+hiddenNull(n.cm.lenderName)+"' style='overflow:auto;padding:5px;'>"; 8 contractTextHtml+="<table class='ui-table ui-table-noborder'>"; 9 contractTextHtml+="<tbody>"; 10 contractTextHtml+="<tr><td>合同編號:</td><td><p>"+hiddenNull(n.cm.contractId)+"</p></td></tr>"; 11 contractTextHtml+="<tr class='ui-table-split'><td>出借人姓名:</td><td><p>"+hiddenNull(n.cm.lenderName)+"</p></td></tr>"; 12 contractTextHtml+="<tr><td>出借人證件類型:</td><td><p>"+hiddenNull(n.cm.lenderIdType)+"</p></td></tr>"; 13 contractTextHtml+="<tr class='ui-table-split'><td>出借人證件號:</td><td><p>"+hiddenNull(n.cm.lenderIdNum)+"</p></td></tr>"; 14 contractTextHtml+="<tr><td>出借金額:</td><td><p>"+hiddenNull(n.cm.lenderAmount)+"</p></td></tr>"; 15 contractTextHtml+="<tr class='ui-table-split'><td>出借人編號:</td><td><p>"+hiddenNull(n.cm.lenderNo)+"</p></td></tr>"; 16 contractTextHtml+="<tr><td>出借人銀行賬號:</td><td><p>"+hiddenNull(n.cm.lenderBankAccount)+"</p></td></tr>"; 17 contractTextHtml+="<tr class='ui-table-split'><td>撮合編號:</td><td><p>"+hiddenNull(n.cm.makeMatchNo)+"</p></td></tr>"; 18 contractTextHtml+="</tbody>"; 19 contractTextHtml+="</table>"; 20 contractTextHtml+="</div>"; 21 $("#textList").append(contractTextHtml); 22 });
形成這種問題的根本緣由在於拼接html打亂了html原有的層次結構,看不出來哪裏是哪裏,沒有了層次結構的代碼,堆在那裏就像是一坨垃圾。
el表達式構造html優勢是可以保持html原有格式,js構造html優勢是速度快省資源,爲何咱們不能把兩者的優勢結合在一塊兒呢?這就是Handlebars.js。
既然要在項目中引入js模版引擎,就必須進行技術選型,嚴格考覈以後,才能夠引入,就好像是木桶效應,不能讓他成爲項目中的短板。
Handlebars.js是一款基於Jquery的插件,以json對象爲數據源,支持邏輯判斷、循環等操做,同時具備很是好的擴展性,體積60KB左右,通過小菜仔細的分析研究,這是一款不可多得的js模版引擎。
Jquery插件,第一步固然要引用Jquery啦,而後引用Handlebars.js便可,僅僅須要這兩個js文件。
1 <script type="text/javascript" src="script/jquery.js"></script> 2 <script type="text/javascript" src="script/handlebars-1.0.0.beta.6.js"></script>
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <META http-equiv=Content-Type content="text/html; charset=utf-8"> 5 <title>each-基本循環使用方法 - by 楊元</title> 6 </head> 7 <body> 8 <h1>each-基本循環使用方法</h1> 9 <!--基礎html框架--> 10 <table> 11 <thead> 12 <tr> 13 <th>姓名</th> 14 <th>性別</th> 15 <th>年齡</th> 16 </tr> 17 </thead> 18 <tbody id="tableList"> 19 20 </tbody> 21 </table> 22 23 <!--插件引用--> 24 <script type="text/javascript" src="script/jquery.js"></script> 25 <script type="text/javascript" src="script/handlebars-1.0.0.beta.6.js"></script> 26 27 <!--Handlebars.js模版--> 28 <!--Handlebars.js模版放在script標籤中,保留了html原有層次結構,模版中要寫一些操做語句--> 29 <!--id能夠用來惟一肯定一個模版,type是模版固定的寫法--> 30 <script id="table-template" type="text/x-handlebars-template"> 31 {{#each student}} 32 <tr> 33 <td>{{name}}</td> 34 <td>{{sex}}</td> 35 <td>{{age}}</td> 36 </tr> 37 {{/each}} 38 </script> 39 40 <!--進行數據處理、html構造--> 41 <script type="text/javascript"> 42 $(document).ready(function() { 43 //模擬的json對象 44 var data = { 45 "student": [ 46 { 47 "name": "張三", 48 "sex": "0", 49 "age": 18 50 }, 51 { 52 "name": "李四", 53 "sex": "0", 54 "age": 22 55 }, 56 { 57 "name": "妞妞", 58 "sex": "1", 59 "age": 18 60 } 61 ] 62 }; 63 64 //註冊一個Handlebars模版,經過id找到某一個模版,獲取模版的html框架 65 //$("#table-template").html()是jquery的語法,不懂的童鞋請惡補。。。 66 var myTemplate = Handlebars.compile($("#table-template").html()); 67 68 //將json對象用剛剛註冊的Handlebars模版封裝,獲得最終的html,插入到基礎table中。 69 $('#tableList').html(myTemplate(data)); 70 }); 71 </script> 72 </body> 73 </html>
經過閱讀本例,讀者已經掌握Handlebars.js一個重要特性:循環。#each能夠理解成循環命令,循環的是json對象中的student屬性。對於每次循環,均可以讀出裏邊的name、sex、age屬性。
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <META http-equiv=Content-Type content="text/html; charset=utf-8"> 5 <title>each-循環中使用this - by 楊元</title> 6 </head> 7 <body> 8 <h1>each-循環中使用this</h1> 9 <!--基礎html框架--> 10 <table> 11 <thead> 12 <tr> 13 <th>姓名</th> 14 <th>性別</th> 15 <th>年齡</th> 16 </tr> 17 </thead> 18 <tbody id="tableList"> 19 20 </tbody> 21 </table> 22 23 <!--插件引用--> 24 <script type="text/javascript" src="script/jquery.js"></script> 25 <script type="text/javascript" src="script/handlebars-1.0.0.beta.6.js"></script> 26 27 <!--Handlebars.js模版--> 28 <!--Handlebars.js模版放在script標籤中,保留了html原有層次結構,模版中要寫一些操做語句--> 29 <!--id能夠用來惟一肯定一個模版,type是模版固定的寫法--> 30 <script id="table-template" type="text/x-handlebars-template"> 31 {{#each this}} 32 <tr> 33 <td>{{name}}</td> 34 <td>{{sex}}</td> 35 <td>{{age}}</td> 36 </tr> 37 {{/each}} 38 </script> 39 40 <!--進行數據處理、html構造--> 41 <script type="text/javascript"> 42 $(document).ready(function() { 43 //模擬的json對象 44 var data = [ 45 { 46 "name": "張三", 47 "sex": "0", 48 "age": 18 49 }, 50 { 51 "name": "李四", 52 "sex": "0", 53 "age": 22 54 }, 55 { 56 "name": "妞妞", 57 "sex": "1", 58 "age": 18 59 } 60 ]; 61 62 //註冊一個Handlebars模版,經過id找到某一個模版,獲取模版的html框架 63 //$("#table-template").html()是jquery的語法,不懂的童鞋請惡補。。。 64 var myTemplate = Handlebars.compile($("#table-template").html()); 65 66 //將json對象用剛剛註冊的Handlebars模版封裝,獲得最終的html,插入到基礎table中。 67 $('#tableList').html(myTemplate(data)); 68 }); 69 </script> 70 </body> 71 </html>
不少時候,咱們拿到的json對象,自己就是一個list,並非map,直接就能夠遍歷,不須要#each student這樣指定遍歷某個屬性。
此時能夠用#each this,表示遍歷當前對象。
this表示當前上下文,很是靈活
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <META http-equiv=Content-Type content="text/html; charset=utf-8"> 5 <title>each嵌套 - by 楊元</title> 6 </head> 7 <body> 8 <h1>each嵌套</h1> 9 <!--基礎html框架--> 10 <div id="dataList"></div> 11 12 <!--插件引用--> 13 <script type="text/javascript" src="script/jquery.js"></script> 14 <script type="text/javascript" src="script/handlebars-1.0.0.beta.6.js"></script> 15 16 <!--Handlebars.js模版--> 17 <!--Handlebars.js模版放在script標籤中,保留了html原有層次結構,模版中要寫一些操做語句--> 18 <!--id能夠用來惟一肯定一個模版,type是模版固定的寫法--> 19 <script id="table-template" type="text/x-handlebars-template"> 20 {{#each this}} 21 {{#each info}} 22 {{../name}}的{{this}}<br> 23 {{/each}} 24 {{/each}} 25 </script> 26 27 <!--進行數據處理、html構造--> 28 <script type="text/javascript"> 29 $(document).ready(function() { 30 //模擬的json對象 31 var data = [{ 32 "name":"張三", 33 "info":[ 34 "眼睛", 35 "耳朵", 36 "鼻子" 37 ] 38 },{ 39 "name":"李四", 40 "info":[ 41 "爸爸", 42 "媽媽", 43 "妻子" 44 ] 45 }]; 46 47 //註冊一個Handlebars模版,經過id找到某一個模版,獲取模版的html框架 48 //$("#table-template").html()是jquery的語法,不懂的童鞋請惡補。。。 49 var myTemplate = Handlebars.compile($("#table-template").html()); 50 51 //將json對象用剛剛註冊的Handlebars模版封裝,獲得最終的html,插入到基礎table中。 52 $('#dataList').html(myTemplate(data)); 53 }); 54 </script> 55 </body> 56 </html>
循環嵌套在稍微複雜點的頁面設計中即會涉及,Handlebars.js徹底支持each嵌套,能夠在each中使用each。
上邊的例子演示了兩個關鍵點:each嵌套的可實現性、如何在each嵌套中讀取父each中的數據。
例子很簡單,info自己是一個信息列表,是屬於某我的的,咱們先用each遍歷全部的人,而後再遍歷每一個人的info信息,這樣就造成了each嵌套。可是咱們想在內層each中獲取外層each的數據,達到「誰的什麼」這樣的顯示效果。
顯然,若是直接在內層each中使用{{name}},是取不到任何數據的,由於內層each的上下文是info,而name屬性在表示人的上下文中。
此時,能夠用{{../name}}從內層each獲取上一級each的name屬性,語法和html的路徑表示同樣,簡單吧?
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <META http-equiv=Content-Type content="text/html; charset=utf-8"> 5 <title>關於循環中索引的使用 - by 楊元</title> 6 </head> 7 <body> 8 <h1>關於循環中索引的使</h1> 9 <!--基礎html框架--> 10 <table> 11 <thead> 12 <tr> 13 <th>序號</th> 14 <th>姓名</th> 15 <th>性別</th> 16 <th>年齡</th> 17 </tr> 18 </thead> 19 <tbody id="tableList"> 20 21 </tbody> 22 </table> 23 24 <!--插件引用--> 25 <script type="text/javascript" src="script/jquery.js"></script> 26 <!--注意!這個例子用的是新版本handlebars,舊版本不支持--> 27 <script type="text/javascript" src="script/handlebars-v1.3.0.js"></script> 28 29 <!--Handlebars.js模版--> 30 <!--Handlebars.js模版放在script標籤中,保留了html原有層次結構,模版中要寫一些操做語句--> 31 <!--id能夠用來惟一肯定一個模版,type是模版固定的寫法--> 32 <script id="table-template" type="text/x-handlebars-template"> 33 {{#each student}} 34 <tr> 35 <td>{{addOne @index}}</td> 36 <td>{{name}}</td> 37 <td>{{sex}}</td> 38 <td>{{age}}</td> 39 </tr> 40 {{/each}} 41 </script> 42 43 <!--進行數據處理、html構造--> 44 <script type="text/javascript"> 45 $(document).ready(function() { 46 //模擬的json對象 47 var data = { 48 "student": [ 49 { 50 "name": "張三", 51 "sex": "0", 52 "age": 18 53 }, 54 { 55 "name": "李四", 56 "sex": "0", 57 "age": 22 58 }, 59 { 60 "name": "妞妞", 61 "sex": "1", 62 "age": 19 63 } 64 ] 65 }; 66 67 //註冊一個Handlebars模版,經過id找到某一個模版,獲取模版的html框架 68 //$("#table-template").html()是jquery的語法,不懂的童鞋請惡補。。。 69 var myTemplate = Handlebars.compile($("#table-template").html()); 70 71 //註冊一個Handlebars Helper,用來將索引+1,由於默認是從0開始的 72 Handlebars.registerHelper("addOne",function(index,options){ 73 return parseInt(index)+1; 74 }); 75 76 //將json對象用剛剛註冊的Handlebars模版封裝,獲得最終的html,插入到基礎table中。 77 $('#tableList').html(myTemplate(data)); 78 }); 79 </script> 80 </body> 81 </html>
序號是指:在循環過程當中,當前循環的索引,說白了,就是當前爲第幾回循環,通常從0開始,Handlebars.js中也是如此。
有什麼用呢?最多見的是在顯示table的時候,給每行加一個序號,清晰的展現出頁面上共有多少條記錄,如上邊的例子。
除此以外,小菜爲了在循環中區分不一樣的id,剛好須要一個序號,確保id不重複,用過bootstrap的童鞋應該知道,好多事件能夠經過id定位,例如Listgroup控件。
廢話少說,在Handlebars.js中,能夠經過{{@index}}來獲取當前的索引,也就是說@index這個變量就表明了當前索引。
在上邊的例子裏,table的序號從0開始不太好,因而註冊了一個Helper,將索引+1。