[分享] Handlebars.js、LESS

提供WOG各方面的技術問題,並提供最新path更新。

版主: 簫哥, 涅魂, 10度C~


涅魂
 
文章: 4463
註冊時間: 2004-01-04 11:17 am
來自: Taiwan
性別: 男生

[分享] Handlebars.js、LESS

文章涅魂 » 2015-06-30 2:52 pm

這篇主要以實驗新工具為主,嘗試看看使用新工具能否讓WOG的開發加容易

Handlebar.js: http://handlebarsjs.com/
樣板引擎的一種,能將程式邏輯與樣板內容盡可能地分離。

LESS: http://lesscss.org/
CSS的變種,能以類似程式般地設計方式來規劃CSS,並轉譯成CSS來使用。

這裡以WOG的Foot頁面來做初步設計,檔案架構如下
代碼: 選擇全部
ROOT
- js
  - libs
    - handlebars-v3.0.3.js
    - jquery-2.0.3.min.js
  - compiled_template.js
- css
   wog_foot.css
- less
  - wog_foot.less
- template
  - foot.hbs

開發時有用Grunt做handlebars與less的自動轉換,把hbs檔案轉換成compiled_template.js,LESS轉成相對應的css
Handlebars的相關程式碼 寫:template/foot.hbs
代碼: 選擇全部
<form action="wog_act.php" method="post" name="menu" target="mission">
   <table class="menu-table">
      <tr>
      <td>
         <table>
            <tr><td class="header"><div id="con_fight">冒險旅程</div></td></tr>
            <tr><td><input id="btnAdventure" type="button" value="冒險開始" name="ats1" onClick="parent.ad_view()" accesskey="a"></td></tr>
            <tr><td><input id="btnStatus" type="button" value="角色狀態" onClick="parent.act_click(\'chara\',\'status_view\')" accesskey="s"></td></tr>            
            <tr><td><input id="btnChampion" type="button" value="冠軍狀態" onClick="parent.act_click(\'chara\',\'cp\')" accesskey="o"></td></tr>
         </table>
      </td>
      <td>
         <table>
            <tr><td class="header">貿易交流</td></tr>
            <tr><td><input id="btnStore" type="button" value="商店街" onClick="parent.select_store()" accesskey="c"></td></tr>
            <tr><td><input id="btnArm" type="button" value="裝備欄" onClick="parent.arm_select(1)" accesskey="e"></td></tr>            
            <tr><td><input id="btnHotel" type="button" value="住 宿" onClick="parent.act_click(\'store\',\'hotel\')" accesskey="h"></td></tr>
         </table>
      </td>
      <td>
         <table>
            <tr><td class="header">對象(<a href="javascript:parent.noname()"><font color="#000000">取消</font></a>)</td></tr>
            <tr><td><input type="text" name="towho" size="4"></td></tr>
            <tr><td><input id="btnTout" type="button" value="偵查對手" onClick="parent.act_click(\'chara\',\'view2\',document.menu.towho.value)" accesskey="v"></td></tr>            
            <tr><td><input id="btnDepot" type="button" value="銀行倉庫" onClick="parent.act_click(\'arm\',\'depot_list\')" accesskey="d"></td></tr>
         </table>
      </td>
      <td>
         <table>
            <tr><td class="header">其他</td></tr>
            <tr><td><input id="btnMission" type="button" value="任務手冊" onClick="parent.mission_ed()" accesskey="b"></td></tr>
            <tr><td><input id="btnSkill" type="button" value="技能手冊" onClick="parent.act_click(\'skill\',\'view\')" accesskey="k"></td></tr>            
            <tr><td><input id="btnInfo" type="button" value="情報中心" onClick="parent.act_click(\'system\',\'view1\')" accesskey="q"></td></tr>
         </table>
      </td>
      </tr>
   </table>
</form>
{{#if viewCopyright}}
<table cellspacing="0" cellpadding="0" align="center">
   <tr>
      <td valign="top" align="center" >
         <b><a href="http://www.et99.net/viewforum.php?f=36" target="_blank">WOG</a> V4 Copyright (C) <a href="http://www.et99.net" target="_blank">ETERNAL</a></b>
      </td>
   </tr>
</table>
{{/if}}

js/compiled_template.js
代碼: 選擇全部
this["template"] = this["template"] || {};
this["template"]["foot"] = Handlebars.template({"1":function(depth0,helpers,partials,data) {
    return "<table cellspacing=\"0\" cellpadding=\"0\" align=\"center\">\r\n   <tr>\r\n      <td valign=\"top\" align=\"center\" >\r\n         <b><a href=\"http://www.et99.net/viewforum.php?f=36\" target=\"_blank\">WOG</a> V4 Copyright (C) <a href=\"http://www.et99.net\" target=\"_blank\">ETERNAL</a></b>\r\n      </td>\r\n   </tr>\r\n</table>\r\n";
},"compiler":[6,">= 2.0.0-beta.1"],"main":function(depth0,helpers,partials,data) {
    var stack1;

  return "<form action=\"wog_act.php\" method=\"post\" name=\"menu\" target=\"mission\">\r\n   <table class=\"menu-table\">\r\n      <tr>\r\n      <td>\r\n         <table>\r\n            <tr><td class=\"header\"><div id=\"con_fight\">冒險旅程</div></td></tr>\r\n            <tr><td><input id=\"btnAdventure\" type=\"button\" value=\"冒險開始\" name=\"ats1\" onClick=\"parent.ad_view()\" accesskey=\"a\"></td></tr>\r\n            <tr><td><input id=\"btnStatus\" type=\"button\" value=\"角色狀態\" onClick=\"parent.act_click(\\'chara\\',\\'status_view\\')\" accesskey=\"s\"></td></tr>            \r\n            <tr><td><input id=\"btnChampion\" type=\"button\" value=\"冠軍狀態\" onClick=\"parent.act_click(\\'chara\\',\\'cp\\')\" accesskey=\"o\"></td></tr>\r\n         </table>\r\n      </td>\r\n      <td>\r\n         <table>\r\n            <tr><td class=\"header\">貿易交流</td></tr>\r\n            <tr><td><input id=\"btnStore\" type=\"button\" value=\"商店街\" onClick=\"parent.select_store()\" accesskey=\"c\"></td></tr>\r\n            <tr><td><input id=\"btnArm\" type=\"button\" value=\"裝備欄\" onClick=\"parent.arm_select(1)\" accesskey=\"e\"></td></tr>            \r\n            <tr><td><input id=\"btnHotel\" type=\"button\" value=\"住 宿\" onClick=\"parent.act_click(\\'store\\',\\'hotel\\')\" accesskey=\"h\"></td></tr>\r\n         </table>\r\n      </td>\r\n      <td>\r\n         <table>\r\n            <tr><td class=\"header\">對象(<a href=\"javascript:parent.noname()\"><font color=\"#000000\">取消</font></a>)</td></tr>\r\n            <tr><td><input type=\"text\" name=\"towho\" size=\"4\"></td></tr>\r\n            <tr><td><input id=\"btnTout\" type=\"button\" value=\"偵查對手\" onClick=\"parent.act_click(\\'chara\\',\\'view2\\',document.menu.towho.value)\" accesskey=\"v\"></td></tr>            \r\n            <tr><td><input id=\"btnDepot\" type=\"button\" value=\"銀行倉庫\" onClick=\"parent.act_click(\\'arm\\',\\'depot_list\\')\" accesskey=\"d\"></td></tr>\r\n         </table>\r\n      </td>\r\n      <td>\r\n         <table>\r\n            <tr><td class=\"header\">其他</td></tr>\r\n            <tr><td><input id=\"btnMission\" type=\"button\" value=\"任務手冊\" onClick=\"parent.mission_ed()\" accesskey=\"b\"></td></tr>\r\n            <tr><td><input id=\"btnSkill\" type=\"button\" value=\"技能手冊\" onClick=\"parent.act_click(\\'skill\\',\\'view\\')\" accesskey=\"k\"></td></tr>            \r\n            <tr><td><input id=\"btnInfo\" type=\"button\" value=\"情報中心\" onClick=\"parent.act_click(\\'system\\',\\'view1\\')\" accesskey=\"q\"></td></tr>\r\n         </table>\r\n      </td>\r\n      </tr>\r\n   </table>\r\n</form>\r\n"
    + ((stack1 = helpers['if'].call(depth0,(depth0 != null ? depth0.viewCopyright : depth0),{"name":"if","hash":{},"fn":this.program(1, data, 0),"inverse":this.noop,"data":data})) != null ? stack1 : "");
},"useData":true});


wog_foot.less的相關程式碼 寫:less/wog_foot.less
代碼: 選擇全部
.menu-table {
   width: 300px;
   border: 0px;
   border-spacing: 0;
   background-color: #2B4686;
   td {
      vertical-align: top;
   }
   .header {
      background-color: #CFD2DC;
      color: #000000;
      height: 22px;
      text-align: center;
   }
   #con_fight { color: #000000;}
   input[name="towho"] {
      line-height: 1.6em;
      width: 6em;
   }
   button {
      line-height: 1em;
   }
}

css/wog_foot.css
代碼: 選擇全部
.menu-table {
  width: 300px;
  border: 0px;
  border-spacing: 0;
  background-color: #2B4686;
}
.menu-table td {
  vertical-align: top;
}
.menu-table .header {
  background-color: #CFD2DC;
  color: #000000;
  height: 22px;
  text-align: center;
}
.menu-table #con_fight {
  color: #000000;
}
.menu-table input[name="towho"] {
  line-height: 1.6em;
  width: 6em;
}
.menu-table button {
  line-height: 1em;
}


wog_foot.htm的<head>內加入這行link標籤
代碼: 選擇全部
<link type="text/css" rel="stylesheet" href="css/wog_foot.css"/>

index.htm的<head>內加入這行<script>標籤
代碼: 選擇全部
<script language="javascript" src="js/libs/handlebars-v3.0.3.js"></script>
<script language="javascript" src="js/compiled_template.js"></script>

js/wog_tool.js的foot_fire() function改寫成以下內容
代碼: 選擇全部
function foot_fire()
{
   w_m(template.foot({viewCopyright: UI.set_frame!=1}));
   var a=Gookie("wog_setui");
   setUI(parseInt(a));
   switch (UI.set_frame)
   {
      case 1:
         dfoot=f;
         p_m();
         UI.set_target=f;
         break;
      case 2:
         dfoot=parent.foot.document;
         p_m();
         UI.set_target=dfoot;
         break;
      default:
         setUI(1);
         dfoot=parent.foot.document;
         p_m();
         UI.set_target=dfoot;
         break;
   }
   Drag.init(f.getElementById("wog_menu"));
};

可以改進的部分還很多,但經過了初步的改寫後,可以看到Foot樣板中的程式邏輯已相當程度地從中分離了,不管是foot.hbs還是foot_fire()內的程式碼與原先相比都較容易維護,而顯示結果與原來的內容相比並無二致。

在LESS部分,將樣式設計的內容自樣板中抽離改放到LESS內,並利用block的概念來規劃樣式表,能讓樣板顯得較為簡潔而且也容易維護LESS。

其他還有很多工具能用,但多次測試後這兩件工具對於已有一定規模的WOG來說要改寫起來比較沒有挫折感,在程式邏輯部分的更動也不太多,可接受度應該不低。 :lol:


圖檔


ETERNAL
 
文章: 2917
註冊時間: 2003-12-03 11:08 pm
性別: 男生

Re: [分享] Handlebars.js、LESS

文章ETERNAL » 2015-06-30 4:47 pm

推一個

現在有些好工具可以讓維護及開發工作變得容易很多

以前資源很少,想實現什麼都要自己寫出來 哈哈


水色論壇 http://www.et99.net
簡恩峻分享


涅魂
 
文章: 4463
註冊時間: 2004-01-04 11:17 am
來自: Taiwan
性別: 男生

Re: [分享] Handlebars.js、LESS

文章涅魂 » 2015-06-30 7:00 pm

用jQuery可以進一步把foot.hbs的event binding分離出來,程式碼如下
js/wog_tool.js的foot_fire() function 寫:
代碼: 選擇全部
function foot_fire()
{
   w_m(template.foot({viewCopyright: UI.set_frame!=1}));
   var a=Gookie("wog_setui");
   setUI(parseInt(a));
   switch (UI.set_frame)
   {
      case 1:
         dfoot=f;
         p_m();
         UI.set_target=f;
         break;
      case 2:
         dfoot=parent.foot.document;
         p_m();
         UI.set_target=dfoot;
         break;
      default:
         setUI(1);
         dfoot=parent.foot.document;
         p_m();
         UI.set_target=dfoot;
         break;
   }
   Drag.init(f.getElementById("wog_menu"));
   $(dfoot)
      .off("click")
      .on("click", "input[id]", _fireButton)
      .on("click", "#noname", noname);
   
   function _fireButton(e) {
      switch($(this).attr("id")) {
         case "btnAdventure": ad_view(); break;
         case "btnStatus": act_click("chara","status_view"); break;
         case "btnChampion": act_click("chara", "cp"); break;
         case "btnStore": select_store(); break;
         case "btnArm": arm_select(1); break;
         case "btnHotel": act_click("store", "hotel"); break;
         case "btnTout": act_click("chara", "view2", $('#towho', dfoot).val()); break;
         case "btnDepot": act_click("arm", "depot_list"); break;
         case "btnMission": mission_ed(); break;
         case "btnSkill": act_click("skill", "view"); break;
         case "btnInfo": act_click("system", "view1"); break;
      }
   }
};

template/foot.hbs 寫:
代碼: 選擇全部
<form action="wog_act.php" method="post" name="menu" target="mission">
   <table class="menu-table">
      <tr>
      <td>
         <table>
            <tr><td class="header"><div id="con_fight">冒險旅程</div></td></tr>
            <tr><td><input id="btnAdventure" type="button" value="冒險開始" name="ats1" accesskey="a"></td></tr>
            <tr><td><input id="btnStatus" type="button" value="角色狀態" accesskey="s"></td></tr>            
            <tr><td><input id="btnChampion" type="button" value="冠軍狀態" accesskey="o"></td></tr>
         </table>
      </td>
      <td>
         <table>
            <tr><td class="header">貿易交流</td></tr>
            <tr><td><input id="btnStore" type="button" value="商店街" accesskey="c"></td></tr>
            <tr><td><input id="btnArm" type="button" value="裝備欄" accesskey="e"></td></tr>            
            <tr><td><input id="btnHotel" type="button" value="住 宿" accesskey="h"></td></tr>
         </table>
      </td>
      <td>
         <table>
            <tr><td class="header">對象(<a id="noname" href="#">取消</a>)</td></tr>
            <tr><td><input id="towho" name="towho" type="text" size="4"></td></tr>
            <tr><td><input id="btnTout" type="button" value="偵查對手" accesskey="v"></td></tr>            
            <tr><td><input id="btnDepot" type="button" value="銀行倉庫" accesskey="d"></td></tr>
         </table>
      </td>
      <td>
         <table>
            <tr><td class="header">其他</td></tr>
            <tr><td><input id="btnMission" type="button" value="任務手冊" accesskey="b"></td></tr>
            <tr><td><input id="btnSkill" type="button" value="技能手冊" accesskey="k"></td></tr>            
            <tr><td><input id="btnInfo" type="button" value="情報中心" accesskey="q"></td></tr>
         </table>
      </td>
      </tr>
   </table>
</form>
{{#if viewCopyright}}
<table cellspacing="0" cellpadding="0" align="center">
   <tr>
      <td valign="top" align="center" >
         <b><a href="http://www.et99.net/viewforum.php?f=36" target="_blank">WOG</a> V4 Copyright (C) <a href="http://www.et99.net" target="_blank">ETERNAL</a></b>
      </td>
   </tr>
</table>
{{/if}}

這樣樣板看起來就更乾淨了 :lol:


圖檔


ETERNAL
 
文章: 2917
註冊時間: 2003-12-03 11:08 pm
性別: 男生

Re: [分享] Handlebars.js、LESS

文章ETERNAL » 2015-09-13 10:23 pm

我回台灣了 什麼時候有空碰面


水色論壇 http://www.et99.net
簡恩峻分享

頭像
齋月
 
文章: 557
註冊時間: 2006-02-27 7:54 am

Re: [分享] Handlebars.js、LESS

文章齋月 » 2015-10-31 12:58 am

最近接觸了 AngularJS & REST API - 突然有一個想法, 想用比較熟悉的WOG來練習 MEAN stack 的開發 - 不知道有沒有人有興趣 :)




ETERNAL
 
文章: 2917
註冊時間: 2003-12-03 11:08 pm
性別: 男生

Re: [分享] Handlebars.js、LESS

文章ETERNAL » 2015-11-02 11:02 am

齋月 寫:最近接觸了 AngularJS & REST API - 突然有一個想法, 想用比較熟悉的WOG來練習 MEAN stack 的開發 - 不知道有沒有人有興趣 :)


AngularJS 我沒接觸過

好做嗎?

好不好玩 :D


水色論壇 http://www.et99.net
簡恩峻分享

頭像
齋月
 
文章: 557
註冊時間: 2006-02-27 7:54 am

Re: [分享] Handlebars.js、LESS

文章齋月 » 2015-11-06 2:56 am

AngularJS 挺不錯的, 也有MVC的concept.

我對Backend比較陌生, 因為以前沒考慮過維護問題, 所以PHP or node.js 的 MVC structure 不太熟

才想用此機會來熟悉熟悉

還希望大家能指點指點 :)




ETERNAL
 
文章: 2917
註冊時間: 2003-12-03 11:08 pm
性別: 男生

Re: [分享] Handlebars.js、LESS

文章ETERNAL » 2015-11-06 4:53 pm

齋月 寫:AngularJS 挺不錯的, 也有MVC的concept.

我對Backend比較陌生, 因為以前沒考慮過維護問題, 所以PHP or node.js 的 MVC structure 不太熟

才想用此機會來熟悉熟悉

還希望大家能指點指點 :)


齋月有沒有在找工作? 我的公司現在缺程式設計師,有沒有興趣? :D


水色論壇 http://www.et99.net
簡恩峻分享


回到 Online FF Battle-WOG官方聯盟推廣處

誰在線上

正在瀏覽這個版面的使用者:沒有註冊會員 和 2 位訪客

cron