什么是單頁應用
單頁應用,是指將用戶視覺上的多個頁面在技術上使用一個載體來實現的應用。
換句話來講,用戶視覺效果,與技術實現的載體,並不是一定要一一對應的。采取哪種技術方案,取決於產品設計、技術組成以及方案之間的優劣平衡。
放到 Web 前端環境中,這個承載了多個視覺效果的載體,就是 html 文件(或 asp,jsp 等)。
為便於描述,本文將使用多個術語。其名稱及對應的含義如下所示:
頁面:技術上的一個html文件;
視圖:視覺上的一頁內容;
初步實現單頁應用
直觀效果的單頁應用,其實現過程其實並不復雜。
我們可以使用 div 或 section 等標簽承載視圖的展現,並通過腳本實現特定視圖的呈現與隱藏。例如:
<!DOCTYPE HTML> <html> <head>...</head> <body> <div id = "view1" class = "view">page1</div> <div id = "view2" class = "view">page2</div> </body> </html>
.view{ display: none; } .view.active{ display: block; }
var find = function(selector){ return document.querySelector(selector); }; find(".view.active").classList.remove("active"); find("#view2.view").classList.add("active");
這可能是最簡單的單頁應用了。
和其它框架相比,View.js為單頁應用開發提供了的以下幾個關鍵特性彰顯了它的比較優勢:
無需配置和開發,視圖導航開箱可用
允許在視圖切換時傳遞任意類型的參數
允許自定義視圖切換動畫
允許自定義視圖配置
以事件驅動地形式完成視圖功能的開發
View.js是為了簡化移動端單頁應用的功能開發而創建的,web前端開發者可以繼續沿用既有技術棧,不會因為使用view.js而面臨較大的沖擊。
需要注意的是,和vue不同,對於使用View.js完成的單頁應用,其HTML文檔仍然由HTML、CSS和JS組成。開發者一如既往地需要手動建立html、css和js文件,並手動完成資源的引用。因為View.js的舞台,是瀏覽器裝載文檔之后的運行時環境。
視圖導航
視圖導航,在視圖切換時由View.js自動完成。下面是一個例子
/* 切換至商品詳情視圖 */ View.navTo("goods-detail", { options: { goodsId: "G01" } });
視圖切換后,頁面URL將自動變更為:http://domain:port/context/index.html#goods-detail!goodsId=G01。
View.js當前僅支持hash形式的地址表示。
視圖傳參
View.js允許以視圖為單位拆分任務,執行多人協作。視圖之間使用參數完成協作。參數在進行視圖切換時傳遞,如下所示:
View.navTo("goods-detail", { options: {/* 使用options傳遞的參數將反饋到地址欄中,因此只能傳遞字符串類型的參數 */ goodsId: "G01" } }); /* ---------------------------------- */ View.navTo("delivery-address-list", { params: {/* 使用params傳遞的參數不會反饋到地址欄中,因此可以是任意被瀏覽器所支持的類型 */ selectCallback: function(selectedAddress){ //... } } }); /* ---------------------------------- */ View.navTo("goods-detail", { params: { goodsId: "G01", }, options: { goodsId: "G02" } }); var view = View.ofId("goods-detail"); view.on("enter", function(){ var goodsId = view.getParameter("goodsId");// --> G01 goodsId = View.getActiveViewOption("goodsId");// --> G02 goodsId = view.seekParameter("goodsId");// --> G01 });
視圖配置
多數情況下,一個視圖的表現和行為是固定的一種。但對於軟件提供商,其同一產品在被多個客戶購買時,會遇到“不同客戶有不同需求,拒絕需求沒收入,答應需求成本高”的窘境。而不同需求的差異點通常也並不高,可能也就只有10-30%左右的差別。但因為10%的差別,就要把源碼硬拷貝2份,對於軟件提供商而言,成本無疑高了許多。
View.js考慮到了這一點。
通過引入視圖配置,開發者可以將視圖開發為多種形態的綜合體,最終以視圖配置的方式指定視圖的具體工作模式或表現形式。如下所示:
var view = View.ofId("register"); /* 默認配置:密碼最少位數 */ view.config.get("password-min-length").setValue(6); /* 默認配置:密碼最多位數 */ view.config.get("password-max-length").setValue(20); /* -------------------------------------------- */ view.find(".submit").addEventListener("click", function(){ var pwd = pwdObj.value.trim(); var minLen = view.config.get("password-min-length").getValue(), maxLen = view.config.get("password-max-length").getValue(); if(pwd.length < min){ alert("密碼長度不能少於" + minLen + "位"); return; } if(pwd.length > max){ alert("密碼長度不能多於" + maxLen + "位"); return; } }); /* -------------------------------------------- */ /* 客戶A的視圖配置 */ /* 重載既有配置:密碼最少位數 */ view.config.get("password-min-length").setValue(10, true);/* 第二個參數用於復寫可能已經存在的值,如果不傳且已經有值,則賦值無效,相當於什么也沒做 */ /* 重載默認配置:密碼最多位數 */ view.config.get("password-max-length").setValue(20, true); /* -------------------------------------------- */ /* 客戶B的視圖配置 */ /* 重載既有配置:密碼最少位數 */ view.config.get("password-min-length").setValue(4, true); /* 重載默認配置:密碼最多位數 */ view.config.get("password-max-length").setValue(10, true);
事件驅動
開發者通過監聽視圖的相關事件來決定執行特定操作的時機。View.js為每個視圖實例預制了如下幾個事件:
ready - 視圖就緒,在視圖第一次進入時觸發;
beforeenter - 視圖即將進入
enter - 視圖進入
afterenter - 視圖進入后
leave - 視圖離開
除此之外,開發者還可以根據自己的業務需要,自行發起並消費事件,如下所示:
var view = View.ofId("myView"); view.on("myevent", function(e){ view.logger.debug("Event name: {}, event data: {}", e.name, e.data); }); //… view.fire("myevent", {a: 1});//-> 0918 10:20:54 [View#myView]: Event name: null, event data: {"a":1}