前端框架擼起來——組件和路由
- 2021 年 11 月 24 日
- 筆記
- 04 Web技術, 13 HTML5, 16 Javascript
框架只有一個html文件,html中只有一個id是app的div,如何點擊一個按鈕或者菜單來顯示對應的頁面呢?最初大家都是通過拼接html字元串,然後再綁定,這樣寫很不優雅,當系統功能模組龐大時,這樣下來難以維護。如何實現模組化以及寫出優雅的程式碼,接下來就是組件和路由的事情。
組件(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。