框架只有一个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。
Gitee: https://gitee.com/known/kui
Github: https://github.com/known/kui