This repository has been archived on 2023-08-30. You can view files and clone it, but cannot push or open issues/pull-requests.
bytedo
/
wcui
Archived
1
0
Fork 0
wcui/js/lib/router/router.js

163 lines
5.3 KiB
JavaScript
Raw Normal View History

2017-03-30 01:40:59 +08:00
define(['yua'], function(){
function Router(){
this.table = {get: []};
this.errorFn = null;
this.history = null;
this.hash = '';
this.started = false;
this.init = {};
}
var defaultOptions = {
prefix: /^(#!|#)[\/]?/, //hash前缀正则
historyOpen: true, //是否开启hash历史
allowReload: true //连续点击同一个链接是否重新加载
};
var isMouseUp = true;
var ruleRegExp = /(:id)|(\{id\})|(\{id:([A-z\d\,\[\]\{\}\-\+\*\?\!:\^\$]*)\})/g;
Router.prototype = {
error: function(callback){
this.errorFn = callback;
},
config: function(opts){
if(this.started)
return console.error('Router config has been set');
this.started = true;
if(!opts.allowReload)
opts.historyOpen = true;
this.init = yua.mix({}, defaultOptions, opts);
},
_getRegExp: function(rule, opts){
var re = rule.replace(ruleRegExp, function(m, p1, p2, p3, p4){
var w = '([\\w.-]';
if(p1 || p2){
return w + '+)';
}else{
if(!/^\{[\d\,]+\}$/.test(p4)){
w = '(';
}
return w + p4 + ')';
}
})
re = re.replace(/(([^\\])([\/]+))/g, '$2\\/').replace(/(([^\\])([\.]+))/g, '$2\\.').replace(/(([^\\])([\-]+))/g, '$2\\-').replace(/(\(.*)(\\[\-]+)(.*\))/g, '$1-$3');
re = '^' + re + '$';
opts.regexp = new RegExp(re)
return opts;
},
_add: function(method, rule, callback){
if(!this.started)
this.config({});
var table = this.table[method.toLowerCase()];
if (rule.charAt(0) !== "/") {
console.error('char "/" must be in front of router rule');
return;
}
rule = rule.replace(/^[\/]+|[\/]+$|\s+/g, '');
var opts = {};
opts.rule = rule;
opts.callback = callback;
yua.Array.ensure(table, this._getRegExp(rule, opts));
},
_route: function(method, hash){
var hash = hash.trim();
var table = this.table[method];
var init = this.init;
if(!init.allowReload && hash === this.history)
return;
if(init.historyOpen){
this.history = hash;
if(yua.ls)
yua.ls('lastHash', hash);
}
for(var i = 0, obj; obj = table[i++];){
var args = hash.match(obj.regexp);
if(args){
args.shift();
return obj.callback.apply(obj, args)
}
}
this.errorFn && this.errorFn(hash);
},
on: function(rule, callback){
this._add('get', rule, callback);
}
}
yua.bind(window, 'load', function(){
if(!yua.router.started)
return;
var prefix = yua.router.init.prefix;
var hash = location.hash;
hash = hash.replace(prefix, "").trim();
yua.router._route('get', hash);
});
if('onhashchange' in window){
window.addEventListener('hashchange', function(event){
if(!isMouseUp)
return;
var prefix = yua.router.init.prefix;
var hash = location.hash.replace(prefix, "").trim();
yua.router._route('get', hash)
})
}
//劫持页面上所有点击事件,如果事件源来自链接或其内部,
//并且它不会跳出本页,并且以"#/"或"#!/"开头那么触发updateLocation方法
yua.bind(document, "mousedown", function(event){
var defaultPrevented = "defaultPrevented" in event ? event['defaultPrevented'] : event.returnValue === false
if (defaultPrevented || event.ctrlKey || event.metaKey || event.which === 2)
return
var target = event.target
while (target.nodeName !== "A") {
target = target.parentNode
if (!target || target.tagName === "BODY") {
return
}
}
if (targetIsThisWindow(target.target)){
if(!yua.router.started)
return;
var href = target.getAttribute("href") || target.getAttribute("xlink:href"),
prefix = yua.router.init.prefix;
if (href === null || !prefix.test(href))
return
yua.router.hash = href.replace(prefix, "").trim();
event.preventDefault();
location.hash = href;
isMouseUp = false;
}
})
yua.bind(document, "mouseup", function(){
if(!isMouseUp){
yua.router._route('get', yua.router.hash);
isMouseUp = true;
}
})
//判定A标签的target属性是否指向自身
//thanks https://github.com/quirkey/sammy/blob/master/lib/sammy.js#L219
function targetIsThisWindow(targetWindow) {
if (!targetWindow || targetWindow === window.name || targetWindow === '_self' || (targetWindow === 'top' && window == window.top)) {
return true
}
return false
}
return yua.router = new Router;
})