框架只有一個html檔案,html中只有一個id是app的div,如何點選一個按鈕或者選單來顯示對應的頁面呢?最初大家都是通過拼接html字串,然後再繫結,這樣寫很不優雅,當系統功能模組龐大時,這樣下來難以維護。如何實現模組化以及寫出優雅的程式碼,接下來就是元件和路由的事情。
- Gitee: https://gitee.com/known/kui
- Github: https://github.com/known/kui
元件(Component)
元件是龐大系統的一個個小的零件,元件可以進行巢狀。系統有多個頁面構成,頁面有多個部件組成,頁面和部件都可以稱之為元件,他們都有共同的屬性和方法。本框架我們約定元件有render、mounted、destroy三個方法。
1)元件的定義
function TestPage() {
//這裡寫元件的私有變數、共有屬性和方法、私有方法
var component1 = new Component1();//私有變數component1
var timer;//計時器
}
2)呈現方法(render)
//這裡是呈現TestPage元件的方法
//dom是根節點app,也可以是其他頁面中的節點
this.render = function(dom) {
$('<div>').html('Component1').appendTo(dom);//呈現一個div
component1.render(dom);//呈現巢狀元件component1
}
3)掛載方法(mounted)
//這裡是載入元件的後端介面資料
this.mounted = function() {
component1.loadData();
timer = setInterval(function() {...}, 1000);
}
4)銷燬方法(destroy)
//這裡是銷燬元件的資源,例如一個setInterval的物件
this.destroy = function() {
clearInterval(timer);
}
5)元件完整程式碼
function TestPage() {
var component1 = new Component1();
var timer;
this.render = function(dom) {
$('<div>').html('Component1').appendTo(dom);
component1.render(dom);
}
this.mounted = function() {
component1.loadData();
timer = setInterval(function() {...}, 1000);
}
this.destroy = function() {
clearInterval(timer);
}
}
路由(Router)
路由是不同元件之前的轉換器,起到元件自由切換的作用。路由可以進行巢狀,即頁面是最頂級的元件,渲染在根節點下面,頁面內部區塊也可以呈現不同的元件。本框架路由只提供兩個方法,即導航和回退,其實路由可以擴充套件更多的方法,如根據name或者模板來路由,這裡暫不實現。本框架暫不支援瀏覽器地址路由,有興趣的同學可以自己實現。
1)路由的定義
//elem是路由的節點物件
//option是路由的配置選項
function Router(elem, option) {
//這裡寫路由的私有變數、共有屬性和方法、私有方法
var _current = {};//儲存當前路由物件
}
2)導航方法(route)
//路由到指定的元件
//item為路由物件,必須包含component屬性
this.route = function(item) {
//呈現前的驗證,例如登入驗證
if (!_option.before(item))
return;
//銷燬當前元件
_destroyComponent();
//設定當前元件
_setCurrent(item);
//執行元件
var component = item.component;
if (component) {
_renderComponent(component);
_mountComponent(item, component);
}
}
3)回退方法(back)
//回退到當前路由的上一個路由
this.back = function() {
_this.route(_current.previous);
}
4)路由完整程式碼
function Router(elem, option) {
//fields
var _option = option || {},
_elem = elem,
_current = {},
_this = this;
//methods
this.route = function (item) {
if (!_option.before(item))
return;
_destroyComponent();
_setCurrent(item);
var component = item.component;
if (component) {
_renderComponent(component);
_mountComponent(item, component);
}
}
this.back = function () {
_this.route(_current.previous);
}
//private
function _destroyComponent() {
var currComp = _current.component;
currComp && currComp.destroy && currComp.destroy();
}
function _setCurrent(item) {
if (!item.previous) {
item.previous = _current; //儲存上一個路由
}
_current = item;
}
function _renderComponent(component) {
if (typeof component === 'string') {
_elem.html(component);//字串元件
} else {
_elem.html('');//清空節點
component.render(_elem);//呈現元件
}
}
function _mountComponent(item, component) {
setTimeout(function () {
_option.after && _option.after(item);//呈現後回撥公共邏輯
component.mounted && component.mounted();//呼叫後臺資料
}, 10);//延時執行,等dom呈現完成後
}
}
下一章我們實現框架根元件App。