Mobile Router.js, a lightweight single page bone for mobile web app
mobile-router.js — A lightweight single page bone for mobile web App.轻量级web端单页面骨架
mobile-router.js-demo是一个关于mobile-router.js如何使用的DEMO,暂时包含:前后端模板共享,后端输出首屏,与其他库自由搭配,动画转场。
mobile-router.js-sample - A mobile-router.js demo like ui-router sample
优势:
-
使用简单、方便、轻量,基于 history、window.onpopstate。
-
支持路由视图嵌套 (1.5.0+)。
-
无依赖,可与其他框架(库)搭配自由使用,例如:
jquery
,zepto
,iscroll
等。 -
任意选择字符串式模板引擎,当然最简单的就是自己拼接字符串了;同时支持异步(远程获取模板,或者去请求数据在前端构建模板);可配置是否缓存结果模板。
-
考虑后端渲染首屏的情况,只需要按结构输出响应的片段即可,利于
SEO
,且可以实现前后端模板公用。 -
自动缓存部分画面,可配置缓存数量,默认3个。
-
每个路由都有对应的
callback
和onDestroy
等配置方法,分别用于显示了对应画面后的回调以及当该画面销毁时回调。 -
利用
CSS animation
控制动画转场(页面切换)效果,也可设置关闭动画效果。 -
“保留”浏览器原生
hash
功能,根据hash
,可自由跳转到对应id
元素位置。 -
可配置
enablePushState
决定是否使用pushstate
功能,默认启用;不启用的话,仅仅影响的是不产生历史,但是路由依旧好使的,也就是还是基于url
的。
一些注意点:
-
不管画面是否已缓存在页面中,只要切换回显示了,那么就会调用
callback
,而callback
中大多数情况需要处理监听事件、操作DOM
,这时候可根据this.cached
来区分;当没有缓存在页面上时为false
,或者缓存在页面上了,但是模板更新了,这时候也为false
。 -
getTemplate
配置方法,如果带有参数,那么该参数就是得到模板字符串后的回调函数,一定要回调的;如果没有参数,直接返回模板字符串即可。这样做,主要是为了考虑异步获取(render)模板的场景。 -
M.history
的默认的 base path 是页面中base
元素的href
的值,如果没有,则默认是/
;也可以在M.history.start()
时传入。 -
对于history、window.onpopstate不支持或者支持不够好的浏览器来说,能够正常匹配对应
route
,也就是说能够正常调用route
配置项中的getTemplate
以及callback
(onDestroy
除外),其他功能都没有,点击链接直接刷新页面。这样就可以在不改变代码的情况下,适配了不支持的浏览器。当然这种情况也可以通过取得M.history.support
来判断,如果不支持的话,可以在调用M.history.start
时设置参数enablePushState
为false
也可以,但不建议,因为没有历史记录了。
使用方法:
M.router.init([
{
path: '/',
cacheTemplate: false, // 针对于当前的route,是否缓存模板
animation: true, // 针对于当前的route,是否有动画
aniClass: 'slideup', // 针对于当前的route,动画类型(效果)
getTemplate: function() {
return '/index';
},
onActive: function() { // 1.5.5+ 当路由被激活时调用,一般此时还没创建 `page-view` 元素
},
callback: function() { // 页面展示出来之后
if (this.cached) return;
// 处理操作...
},
onDestroy: function() {
// 例如,处理一些解绑操作,销毁和DOM关联
},
onEnter: function(paramName) { // 1.5.3+ // 页面将要显示的时候
},
onLeave: function() { // 1.5.3+ // // 页面将要隐藏的时候
}
},
{ // 支持 redirectTo 语法,可以是直接的 url 还可以是函数 (1.5.5+)
path: '/redirectTo/:rtPath',
redirectPushState: false, // 默认 true, 当激活redirectTo的时候是否启用`pushState`
redirectTo: function(rtPath) {
console.log('redirectTo', arguments, this);
return '/' + rtPath;
}
},
{ // support redirectTo , string url or function (1.5.5+)
// 如果当前的route配置有getTemplate的话,此时会表现的像正常的
// route一样依旧会创建`page-view`、会调用回调函数们、会做动画等。
// 当正常行为结束之后(route的callback被调用之后)会触发redirectTo的逻辑
path: '/contacts',
getTemplate: contacts.getTemplate,
onEnter: contacts.onEnter,
onLeave: contacts.onLeave,
callback: contacts.controller,
onDestroy: contacts.onDestroy,
redirectTo: '/contacts/list',
redirectPushState: false,
children: { // Nested routes & views! (1.5.0+)
viewsSelector: '.content',
cacheViewsNum: 1,
routes: [
{
// all contacts
path: '/list',
getTemplate: list.getTemplate,
onEnter: list.onEnter,
onLeave: list.onLeave,
callback: list.controller,
onDestroy: list.onDestroy
}
]
}
},
{
path: '/m/:paramName',
cacheTemplate: false, // 针对于当前的route,是否缓存模板
getTemplate: function(cb) {
// 这里模拟异步得到模板内容
var that = this;
// that.params 参数信息
// that.query query信息
setTimeout(function() {
cb('/m/' + that.params.paramName);
}, 200);
},
callback: function(paramName) {
if (this.cached) return;
// 处理操作...
},
onDestroy: function() {
// 例如,处理一些解绑操作,销毁和DOM关联
}
},
{ // 嵌套!!(1.5.0+)
path: '/b/:bid',
getTemplate: function(cb) {
var path = this.path.substr(1);
setTimeout(function() {
var lis = '';
var t;
for (var i = 1; i <= 4; i++) {
t = path + '/s' + i;
lis += '<li><a href="' + t + '">/' + t + '</a></li>';
// 或者:(这样的话 不会对地址栏有影响)
// lis += '<li><a href="#" data-href="' + t + '">/' + t + '</a></li>';
}
cb(
'<ul class="nav">' + lis + '</ul>'
);
}, 200);
},
callback: function() {
console.log('callback:/b', this, arguments);
},
onDestroy: function() {
// 当前被销毁时调用
console.log('destroy:/b', this, arguments);
},
children: {
/* 这些配置项 默认继承自 parent */
viewsSelector: '',
viewClass: 'sub-view-b',
maskClass: 'mask',
showLoading: true,
cacheViewsNum: 3,
cacheTemplate: true,
animation: true,
aniClass: 'slide',
routes: [
{
path: '/:subB', // '/b/:bid' + '/:subB'
/* 这里依旧可以设置 */
cacheTemplate: false, // 针对于当前的route,是否缓存模板
animation: true, // 针对于当前的route,是否有动画
aniClass: 'slideup', // 针对于当前的route,动画类型(效果)
getTemplate: function(cb) {
var that = this;
setTimeout(function() {
cb('<div>' + that.path + '<p>sub content</p></div>');
}, 200);
},
callback: function() {
console.log('sub callback b', this, arguments);
},
onDestroy: function() {
console.log('sub destroy b', this, arguments);
}
}
]
}
}
], {
/*是否缓存模板*/
cacheTemplate: true,
/*views容器选择器 如果为空,或者没有符合元素,那么views的容器元素就为body了*/
viewsSelector: '',
/*view的class 默认会有 page-view 的 class 这里配置的是其他增加的 class */
viewClass: 'page-view2 page-view3',
/*是否有动画*/
animation: true,
/*有动画的话,动画的类型*/
aniClass: 'slide',
/*蒙层class 主要是显示loading时的蒙层*/
maskClass: 'mask',
/*显示loading*/
showLoading: true,
/*缓存view数*/
cacheViewsNum: 3
});
// 也可以通过这种形式添加
M.router.add('/ddd/{dddID:int}', function(dddID) {
// 这是 callback 回调
}, {
cacheTemplate: true,
getTemplate: function() {
return '/ddd/' + this.params.dddID;
},
onDestroy: function() {
// destroy
}
});
/* 监听route change */
/* routeChangeStart 是刚开始的时候被触发,此时还没有调用getTemplate得到模板内容 */
M.router.on('routeChangeStart', function(currentRouteState) {
});
/*已经完成动画切换(如有动画效果的话)显示出来之后触发*/
M.router.on('routeChangeEnd', function(currentRouteState) {
});
// 开始 监听history
M.history.start({
// base: '/', // base path
// enablePushState: true // 启用pushstate
});
关于配置
animation
、aniClass
和cacheTemplate
配置,依次取的是链接元素上的data-xxx
->单个route规则中对一个的配置项->整体route配置规则中的配置。
examples中示例
-
index.html
: 基本使用,都是默认配置,主要是关于getTemplate
的2中方式以及在链接元素加入data-rel=back
(反方向动画)配置。 -
index1.html
: 在”/c”中利用data-href
达到不更新浏览器地址切换示例,且演示了如何才能局部禁用动画切换效果。 -
index2.html
: 关闭动画示例。 -
index3.html
: 不缓存模板示例。 -
index4.html
: 全局更改动画class示例。 -
index5.html
: 局部更改动画class的两种方式示例。 -
index6.html
: 局部更改缓存模板的两种方式示例。 -
index7.html
:M.history
禁用掉pushstate示例。 -
index8.html
: 嵌套路由视图示例。 -
requirejs/
: 使用 require.js 示例
后端渲染
只需要在响应时加入对应的页面结构即可:
<div class="page-view">后端渲染内容</div>
这是因为默认第一次初始化时,会查找页面上带有viewClass
的元素,如果找到了,且innerHTML
不为空,那么就不会再去调用getTemplate
来得到模板内容了。
代码风格
没有用空格,而是用的tab
。