由於後台模板系統的強大,如rails的erb,javascript的模板系統一直處於被打壓狀態,但又由於背景技術發展過快,日新月異,以及Ajax應用的普及,javascript還是有一藉之地的。如我們要從後台返回一個HTML片斷,但事實上我們永遠只能返迴文本(responseText)或responseXML,如果你得到是json,其實後台已稍稍調用javascript把它eval成json。
好了,既然我們知道它有用武之處,那麼這模板系統的規模應多大呢?或者說,它應該有什麼功能呢?問題很簡單,我們看一下那些後台模板系統就知了。後台模板發展了這麼多年,非常成熟了。因此我們做的問題就是取捨。
<table> <% foreach $topic in param.topic %> <tr class="topic"> <td><%= $topic.renderLink() %></td> <td><%= $topic.creator.renderLink() %></td> <td> <% $count = topic.comments.count() - 1 %> <% if $count == 1 %> 1 Post <% elseif $count > 1 %> <%= $count %> Posts <% else %> <% end %> </td> <td nowrap><%= $topic.createDate | format "dd.MM.yy - HH:mm" %></td> </tr> <% end %> </table>
這是網上找到一個樣本,有分支,有迴圈,還有變數。像分支與迴圈,我覺得實現不應該與普通標籤混在一起,貌似jsp mode1就是這個樣子,很難維護。另外,我們也不得不注意一個問題,就是RSS。現在許多網站都支援訂閱。如果前面是用以下方式設計會死得很慘:
<ul><!-- for(var i=0; i<supplies.length; i++) { //--> <li><!--= supplies[i] //--></li><li><!--= } //--></li></ul>
情況同現在我的部落格用的文法高亮差不多。為了實現高亮,SyntaxHighlighter會把目標pre改成一個div,裡面填充了許多設定了各種樣式的span,於是我們就看到五顏六色。但在google Reader一看,javascript失效了。因此我們得出一個結論,前台的模板系統不應該在全頁面範圍使用。它只應處理那些臨時產生的HTML片斷。如Ajax提交的回複,這就省得重新整理頁面。
由於<% 與 %gt;與許多後台語言的模板系統發生衝突,直接用靜態頁面幹活的日子不多了,因此我們就不能用這種格式了。我推薦使用rails的#{},括弧裡面是替換的東西。
下面是我的微型模板系統,比Ext還少。
dom.Template = dom.factory({ init:function(template, pattern){ this.template = String(template); this.pattern = pattern || dom.Template.Pattern; }, compile: function(object) { return this.template.replace(this.pattern, function(displace,variable){ variable = dom.trim(variable) return displace = object[variable] }); }, statics:{Pattern:/#\{([^}]*)\}/mg} });
把它修改成能獨立啟動並執行代碼,就是下面這個樣子:
var Template = function(template, pattern){ this.template = String(template); this.pattern = pattern || Template.Pattern; } Template.Pattern = /#\{([^}]*)\}/mg; Template.trim = String.trim || function(str){ return str.replace(/^\s+|\s+$/g, '') } Template.prototype ={ constructor:Template, compile: function(object) { return this.template.replace(this.pattern, function(displace,variable){ variable = Template.trim(variable) return displace = object[variable] }); } }
使用:
var data = "<div>Name: <b>#{name}</b> Blog: <a href='#{href}'>#{blog }</a></div>"; var t = new Template(data); var objs = {name:"司徒正美", blog:"RubyLouvre", href:"http://www.cnblogs.com/rubylouvre/"} var result = t.compile(objs); alert(result)
如你們所見,功能非常少,就是替換變數,實現格式與可變內容相分離。執行結果,我們可以用innerHTML把它添加到頁面中。
</p><p><!doctype html><br /><html lang="en"><br /> <head><br /> <meta charset="utf-8" /><br /> <meta content="IE=8" http-equiv="X-UA-Compatible"/><br /> <title>javascript 模板系統 by 司徒正美</title></p><p> <script type="text/javascript"></p><p> var Template = function(template, pattern){<br /> this.template = String(template);<br /> this.pattern = pattern || Template.Pattern;<br /> }<br /> Template.Pattern = /#\{([^}]*)\}/mg;<br /> Template.trim = String.trim || function(str){<br /> return str.replace(/^\s+|\s+$/g, '')<br /> }<br /> Template.prototype ={<br /> constructor:Template,<br /> compile: function(object) {<br /> return this.template.replace(this.pattern, function(displace,variable){<br /> variable = Template.trim(variable)<br /> return displace = object[variable]<br /> });<br /> }<br /> }<br /> window.onload = function(){<br /> var data = "<div>Name: <b>#{name}</b> Blog: <a href='#{href}'>#{blog }</a></div>";<br /> var t = new Template(data);<br /> var objs = {name:"司徒正美",<br /> blog:"RubyLouvre",<br /> href:"http://www.cnblogs.com/rubylouvre/"}<br /> var result = t.compile(objs);<br /> document.body.innerHTML = result<br /> }</p><p> </script></p><p> </head><br /> <body></p><p> </body><br /></html><br />
運行代碼