Skip to content

簡單好用!JQM 跟 Backbone 做 Web 用戶介面

Published: 8 分鐘

山姆鍋對 JavaScript 大多數框架都不算熟悉,但因為《我.影化身》專案需要提供 Web 介面, 不得已也要選擇符合自己需要的框架來運用一下。幸好,我的目標只是一個相對簡單的使用者介面, 讓這個過程縮短不少時間,最後決定使用 JQuery Mobile + Backbone 這樣的框架組合。

為什麼選擇使用 Web 用戶介面?

《我.影化身》專案有桌面環境用戶介面的需求,也嘗試過使用 Qt 這種跨平台的程式庫。 但山姆鍋對於產生的發行包因為這樣就要多將近 20MB 的大小一直覺得耿耿於懷,雖然這只是個人偏好問題, 還是希望有一個較輕量的跨平台用戶介面。

另外一個做法就是使用各個平台的特有程式庫來開發 UI,對於 Python 程式,這表示:

  • 在 Windows 使用 PyWin32
  • 在 OS X 使用 PyObjC
  • 在 Linux 使用 PyGObject

理論上是可行,但要同時使用不同 API 在不同平台開發 UI, 只要 UI 稍微複雜點, 開發的困難度就會需要每個平台一個專職工程師了。《我.影化身》的確有使用上述 程式庫來整合桌面環境的訊息通知機制以及選單,但要開發完整 UI,即使像是《我.影化身》這種設定不需要複雜 UI 的程式,難度還是太高了。其它如 Toga, PyGUI 等等特殊的跨平台 UI 程式庫都因為缺乏專案所需的功能而無法採用。

不管原因為何,最後決定使用 Web 技術來提供跨平台 UI, 似乎也是很合理的方案。

為什麼選擇 JQuery Mobile + Backbone?

由於專業上需要,一直以來山姆鍋都有持續在關注 JavaScript 應用框架的發展, 也常常對於如雨後春筍般出現的新框架感到無所適從,所以之前都僅止於了解,並沒有太多實際運用的經驗。 如今要選擇專案所使用的框架,自然要先說說專案的需求:

提供一個類似應用程式(App)的用戶介面
:   因為這個專案就是個應用程式。

2.

不用太多 HTML5, CSS3 設計

:   作為工程師,山姆鍋對於設計的美感真的不在行。

3.

使用現有的用戶介面元件

:   希望開發的方式可以使用元件概念撰寫,也就是有明確的 Button, List,
    Table 這樣的概念。

4.

同時支援桌面、平板以及手機裝置

:   沒有太多時間使用不同的框架。

應該也有其它方案符合需求,像是 Sencha Touch 等,但個人偏好 JQuery Mobile。 作為 UI 框架, JQuery Mobile 基本功能完整,但要開發應用總還是希望程式要有更好的結構, 這就需要考慮採用其它應用框架來輔助,目前跟 JQuery Mobile 搭配最好的看來是 Backbone。

雖然網路上有許多關於 JQuery Mobile + Backbone 的教學文章,JQuery Mobile 官網甚至有提供示範案例,但這些例子大多假設專案需求龐大,硬是要使用 RequireJS 來提供模組化開發機制。 對於《我.影化身》這樣的專案來說,使用 RequireJS 總有點太過了1 。 雖然網路上也找得到關於只使用 JQuery Mobile

  • Backbone 的範例,但事情如果順利的話, 就不會有這篇文章了!

問題出在哪?

老實說,山姆鍋對 JavaScript 相關框架真的不熟,只是一邊開發一邊學習。 對於網路找到的 JQuery Mobile + Backbone 範例為何不能正常運作也沒有時間深入了解, 也許是單純版本問題,或者只是山姆鍋眼睛脫窗哪裏沒有設定好!不管怎樣,本來認為一件簡單的事情, 卡了一段時間後終於試出來一個可以運作的組合。

除了 JQuery,JQM 本身並不依賴其它程式庫,雖說是完整的框架,但因為它缺少其它 MV* 應用框架的功能, 讓它其實更像 Twitter Bootstrap 這種 UI 框架。為了開發完整的應用,通常還是搭配 Backbone 這樣的應用框架。

但因為 JQM 有自己的頁面路由(page routing)的機制,所以需要設定讓它不處理這部分功能,而由 Backbone 全權處理。JQM 相關的設定在 /js/jqm-config.js 這個檔案:

// JQM config
$(document).on("mobileinit", function () {
    $.mobile.ajaxEnabled = false;
    $.mobile.linkBindingEnabled = false;
    $.mobile.hashListeningEnabled = false;
    $.mobile.pushStateEnabled = false;
    $.mobile.defaultPageTransition = "fade";
    $.mobile.autoInitializePage = false;

    $("div[data-role='page']").on("pagehide", function (event, ui) {
        $(event.currentTarget).remove();
    });
});
\'mobileinit\' 事件
:   在 JQM 完成初始化前會呼叫此事件,所以在此設定 JQM。

-

ajaxEnabled, linkBindingEnabled, pushStateEnabled 都設為 false

:   分別讓 JQM 不使用 Ajax 方式動態載入頁面, 不處理超連結點選事件,
    以及瀏覽器的導航歷史管理(navigation history),這些都會干擾
    Backbone 的運作。

-

hashListeningEnabled 設為 false

:   告訴 JQM 不要處理瀏覽器 URL hash 更動事件。 URL
    hash就是瀏覽器網址中 \'\#\' 那個部分,
    這個部分按照規範是不會傳給後端伺服器,只能在網頁中存取。JQM 跟
    Backbone 就是利用這個 hash 來決定要使用的頁面。

-

由於 JQM 不再負責頁面導航管理,需要由我們自己完成舊的頁面資料從 DOM 中移除的工作

:   `pagehide` 事件處理便是用來完成這個工作。

有了這樣的設定,基本上就可以使用 Backbone 來處理前端頁面導航以及其它功能。

其它注意事項

有幾個在實際開發中遇到的問題:

動態產生 JQM 頁面內容時,可能會發現網頁呈現不太正常
:   這點在專案樣板中沒有實例。這是因為 JQM
    沒有機會套用樣式到新增的網頁元素,需要特別通知 JQM:

    ``` javascript
    $(this.el).trigger("create");
    ```

    如果您有其它更好的方式,請不吝指教。

2.

新版本的更換頁面方式

:   新版本的 JQM 管理頁面的方式有更動,改為下列方式:

    ``` javascript
    $(":mobile-pagecontainer").pagecontainer( "change", $(page.el), { changeHash: false});
    ```

    網路上找到的文章大多使用舊的方法,也就是:

    ``` javascript
    $.mobile.changePage($(page.el), {changeHash:false});
    ```

3.

jqm-config.js 的引入順序

:   `/js/jqm-config.js` 是用來設定 JQM, 它必須在 JQuery
    之後, JQM 之前在網頁中引入,如:
<script src="/js/jquery.min.js"></script>
<script src="/js/jqm-config.js"></script>
<script src="/js/jquery.mobile.min.js"></script>

JQM + Backbone 專案樣板

為了方便未來使用,山姆鍋在 GitHub 上整理了一個專案樣板:https://github.com/sampot/jqm-backbone-template

想要更實際的例子?那就請直接參考《我.影化身》的前端用戶介面實作(webfront):https://github.com/eavatar/eavatar-me

結語

山姆鍋其實很喜歡 AngularJS 這個應用框架,但對於它的運作方式不是很了解,所以不在這個專案採用。 在實際使用後,發現 JQM + Backbone 這樣的組合還蠻不錯的:夠簡單、運作流程容易理解。 對於只需要簡單 Web UI 的應用專案,這是個不錯的選擇。

參考資料


Footnotes

  1. 如果預期專案需要多人一起開發或者功能較複雜,建議考慮使用 RequireJS。

郭信義 (Sam Kuo)

奔騰網路科技技術長,專長分散式系統、Web 應用與雲端服務架構、設計、開發、部署與維運。工作之餘,喜歡關注自由軟體的發展與應用,偶爾寫一下部落格文章。