san-router
Advanced tools
Comparing version 1.2.4 to 2.0.0
@@ -1,1 +0,1 @@ | ||
!function(t){function e(t){switch(typeof t){case"object":return t;case"string":return document.querySelector?document.querySelector(t):document.getElementById(t.replace(/#/i,""))}}function r(t){var e={hash:"",queryString:"",params:{},query:{},path:t},r=e.path.indexOf("#");r>=0&&(e.hash=e.path.slice(r+1),e.path=e.path.slice(0,r));var n=e.query,i=e.path.indexOf("?");if(i>=0){e.queryString=e.path.slice(i+1),e.path=e.path.slice(0,i);for(var o=e.queryString.split("&"),s=0;s<o.length;s++){var a=o[s],h=a.indexOf("="),c="";h>0&&(c=a.slice(h+1),a=a.slice(0,h));var u=decodeURIComponent(a);c=decodeURIComponent(c),n.hasOwnProperty(u)?n[u]=[].concat(n[u],c):n[u]=c}}return e}function n(t){if(!t)return"";if("string"==typeof t)return t;var e,r=t.query,n=t.params,i=t.path||"",o=[];if(i)for(var s=i.split("/"),a=0,h=s.length;a<h;a++){var c=s[a];if(/^:[a-z0-9_-]+$/.test(c)){e=!0;var u=c.slice(1);o.push(n&&n[u]||r&&r[u])}else o.push(c)}var p=t.queryString||"";if(0===p.indexOf("?")&&(p=p.slice(1)),!p&&r&&(!e||n)){var f=!0;for(var l in r)r.hasOwnProperty(l)&&(p+=(f?"":"&")+l+"="+encodeURIComponent(r[l]),f=!1)}return o.join("/")+(p&&"?")+p}function i(t,e){var n=r(t),i=r(e),o=n.path;if(0===o.indexOf("/"))return t;var s;if(o){var a=o.split("/"),h=i.path.split("/");h.pop();for(var c=0;c<a.length;c++){var u=a[c];switch(u){case"..":h.pop();break;case".":break;default:h.push(u)}}""!==h[0]&&h.unshift(""),s=h.join("/")}else s=i.path;return s+(n.queryString?"?"+n.queryString:"")}function o(){}function s(){var t=location.href.indexOf("#");return t<0?"/":location.href.slice(t+1)||"/"}function a(){this.current=s(),this.referrer="";var t=this;this.hashChangeHandler=function(){t.redirect(s())}}function h(){return location.pathname+location.search}function c(){this.current=h(),this.referrer="";var t=this;this.popstateHandler=function(){t.referrer=t.current,t.current=h(),t.fire("redirect",{url:t.current,referrer:t.referrer})}}function u(){return(++d).toString()}function p(t){return t.prototype&&(5===t.prototype.nodeType||"san-cmpt"===t.prototype._type)}function f(t){return function(e){function n(){v>0&&(h<t.listeners.length?(t.listeners[h].call(t,y,a.config),v>0&&i()):o())}function i(){v=1,h++,n()}function o(){if(s)t.doRoute(s,a);else for(var e=t.routeAlives.length;e--;)t.routeAlives[e].component.dispose(),t.routeAlives.splice(e,1)}for(var s,a=r(e.url),h=0;h<t.routes.length;h++){var c=t.routes[h],u=c.rule.exec(a.path);if(u){s=c;for(var p=c.keys||[],f=1;f<u.length;f++){var l=p[f]||f,d=u[f];a.query[l]=d,a.params[l]=d}a.referrer=e.referrer,a.config=c.config;break}}var h=0,v=1,y={url:e.url,hash:a.hash,queryString:a.queryString,query:a.query,params:a.params,path:a.path,referrer:a.referrer,config:a.config,resume:i,suspend:function(){v=0},stop:function(){v=-1}};n()}}function l(t){t=t||{};var e=t.mode||"hash";if("html5"===e&&!c.isSupport)throw new Error("[SAN-ROUTER ERROR] Your navigator doesn't supports HTML5!");this.routes=[],this.routeAlives=[],this.listeners=[],this.locatorRedirectHandler=f(this),this.setMode(e)}o.prototype.on=function(t,e){"function"==typeof e&&(this._eventListeners||(this._eventListeners={}),this._eventListeners[t]||(this._eventListeners[t]=[]),this._eventListeners[t].push(e))},o.prototype.un=function(t,e){if(this._eventListeners&&this._eventListeners[t])if(e)for(var r=this._eventListeners[t],n=r.length;n--;)r[n]===e&&r.splice(n,1);else this._eventListeners[t]=[]},o.prototype.fire=function(t,e){if(!t)throw new Error("No event type specified");var r=this._eventListeners&&this._eventListeners[t];if(r)for(var n=0;n<r.length;n++)r[n](e)},a.prototype=new o,a.prototype.constructor=a,a.prototype.start=function(){window.addEventListener&&window.addEventListener("hashchange",this.hashChangeHandler,!1),window.attachEvent&&window.attachEvent("onhashchange",this.hashChangeHandler)},a.prototype.stop=function(){window.removeEventListener&&window.removeEventListener("hashchange",this.hashChangeHandler,!1),window.detachEvent&&window.detachEvent("onhashchange",this.hashChangeHandler)},a.prototype.redirect=function(t,e){e=e||{},t=i(t,this.current);var r=this.current,n=t!==r;n?(this.referrer=r,this.current=t,location.hash=t):r=this.referrer,!n&&!e.force||e.silent||this.fire("redirect",{url:t,referrer:r})},a.prototype.reload=function(){this.redirect(this.current,{force:!0})},c.prototype=new o,c.prototype.constructor=c,c.prototype.start=function(){window.addEventListener("popstate",this.popstateHandler)},c.prototype.stop=function(){window.removeEventListener("popstate",this.popstateHandler)},c.prototype.redirect=function(t,e){e=e||{},t=i(t,this.current);var r=this.current,n=t!==r;n&&(this.referrer=r,this.current=t,history.pushState({},"",t)),!n&&!e.force||e.silent||this.fire("redirect",{url:t,referrer:r})},c.prototype.reload=function(){this.fire("redirect",{url:this.current,referrer:this.referrer})},c.isSupport="pushState"in window.history;var d=365611;l.prototype.listen=function(t){this.listeners.push(t)},l.prototype.unlisten=function(t){for(var e=this.listeners.length;e--;)this.listeners[e]===t&&this.listeners.splice(e,1)},l.prototype.start=function(){return this.isStarted||(this.isStarted=!0,this.locator.on("redirect",this.locatorRedirectHandler),this.locator.start(),this.locator.reload()),this},l.prototype.stop=function(){return this.locator.un("redirect",this.locatorRedirectHandler),this.locator.stop(),this.isStarted=!1,this},l.prototype.setMode=function(t){if(t=t.toLowerCase(),this.mode!==t){this.mode=t;var e=!1;switch(this.isStarted&&(this.stop(),e=!0),t){case"hash":this.locator=new a;break;case"html5":this.locator=new c}return e&&this.start(),this}},l.prototype.doRoute=function(t,e){for(var r=!1,n=this.routeAlives.length;n--;){var i=this.routeAlives[n];i.id===t.id?(i.component.data.set("route",e),"function"==typeof i.component.route&&i.component.route(),r=!0):(i.component.dispose(),this.routeAlives.splice(n,1))}if(!r)if(t.Component)if(p(t.Component))this.attachCmpt(t,e);else{var o=this;t.Component().then(function(r){p(r)?t.Component=r:r.__esModule&&p(r.default)&&(t.Component=r.default),o.attachCmpt(t,e)})}else t.handler.call(this,e)},l.prototype.attachCmpt=function(t,r){var n=this,i=new t.Component;i.$router=this,i.data.set("route",r),"function"==typeof i.route&&i.route();var o=t.target,s=e(o);if(!s)throw new Error('[SAN-ROUTER ERROR] Attach failed, target element "'+t.target+'" is not found.');i.attach(s),this.routeAlives.push({component:i,id:t.id}),"function"==typeof t.handler&&setTimeout(function(){t.handler.call(n,r)})},l.prototype.add=function(t){var e=t.rule,r=[""];if("string"==typeof e){var n=e.replace(/\/:([a-z0-9_-]+)(?=\/|$)/gi,function(t,e){return r.push(e),"/([^/\\s]+)"});e=new RegExp("^"+n+"$","i")}if(!(e instanceof RegExp))throw new Error("[SAN-ROUTER ERROR] Rule must be string or RegExp!");var i=u();return this.routes.push({id:i,rule:e,handler:t.handler,keys:r,target:t.target||"#main",Component:t.Component,config:t}),this},l.prototype.push=function(t,e){(t=n(t))&&this.locator.redirect(t,e)};var v=new l,y={Link:{template:'<a href="{{hrefPrefix}}{{href}}" onclick="return false;" on-click="clicker($event)" target="{{target}}" class="{{isActive ? activeClass : \'\'}}"><slot/></a>',clicker:function(t){var e=this.data.get("href");"string"==typeof e&&v.locator.redirect(e.replace(/^#/,"")),t.preventDefault?t.preventDefault():t.returnValue=!1},inited:function(){var t=this;this.routeListener=function(e){t.data.set("isActive",e.url===t.data.get("href"))},this.routeListener({url:v.locator.current}),v.listen(this.routeListener)},disposed:function(){v.unlisten(this.routeListener),this.routeListener=null},initData:function(){return{isActive:!1,hrefPrefix:"hash"===v.mode?"#":""}},computed:{href:function(){return i(this.data.get("to")||"",v.locator.current)}}},router:v,Router:l,HashLocator:a,HTML5Locator:c,resolveURL:i,parseURL:r,stringifyURL:n,version:"1.2.4"};"object"==typeof exports&&"object"==typeof module?exports=module.exports=y:"function"==typeof define&&define.amd?define("san-router",[],y):t.sanRouter=y}(this); | ||
!function(t){function e(t){switch(typeof t){case"object":return t;case"string":return document.querySelector?document.querySelector(t):document.getElementById(t.replace(/#/i,""))}}function r(t){var e={hash:"",queryString:"",params:{},query:{},path:t},r=e.path.indexOf("#");r>=0&&(e.hash=e.path.slice(r+1),e.path=e.path.slice(0,r));var n=e.query,o=e.path.indexOf("?");if(o>=0){e.queryString=e.path.slice(o+1),e.path=e.path.slice(0,o);for(var i=e.queryString.split("&"),s=0;s<i.length;s++){var a=i[s],u=a.indexOf("="),h="";u>0&&(h=a.slice(u+1),a=a.slice(0,u));var c=decodeURIComponent(a);h=decodeURIComponent(h),n.hasOwnProperty(c)?n[c]=[].concat(n[c],h):n[c]=h}}return e}function n(t){if(!t)return"";if("string"==typeof t)return t;var e,r=t.query,n=t.params,o=t.path||"",i=[];if(o)for(var s=o.split("/"),a=0,u=s.length;a<u;a++){var h=s[a];if(/^:[a-z0-9_-]+$/.test(h)){e=!0;var c=h.slice(1);i.push(n&&n[c]||r&&r[c])}else i.push(h)}var p=t.queryString||"";if(0===p.indexOf("?")&&(p=p.slice(1)),!p&&r&&(!e||n)){var f=!0;for(var l in r)r.hasOwnProperty(l)&&(p+=(f?"":"&")+l+"="+encodeURIComponent(r[l]),f=!1)}return i.join("/")+(p&&"?")+p}function o(t,e){var n=r(t),o=r(e),i=n.path;if(0===i.indexOf("/"))return t;var s;if(i){var a=i.split("/"),u=o.path.split("/");u.pop();for(var h=0;h<a.length;h++){var c=a[h];switch(c){case"..":u.pop();break;case".":break;default:u.push(c)}}""!==u[0]&&u.unshift(""),s=u.join("/")}else s=o.path;return s+(n.queryString?"?"+n.queryString:"")}function i(){}function s(){var t=location.href.indexOf("#");return t<0?"/":location.href.slice(t+1)||"/"}function a(){this.current=s(),this.referrer="";var t=this;this.hashChangeHandler=function(){t.redirect(s())}}function u(){return location.pathname+location.search}function h(){if(!h.isSupport)throw new Error("[SAN-ROUTER ERROR] Your navigator doesn't supports HTML5!");this.current=u(),this.referrer="";var t=this;this.popstateHandler=function(){t.referrer=t.current,t.current=u(),t.fire("redirect",{url:t.current,referrer:t.referrer})}}function c(){return(++_).toString()}function p(t){return t.prototype&&(5===t.prototype.nodeType||"san-cmpt"===t.prototype._type)}function f(t){t=t||{};var e=t.mode||"hash";this.routes=[],this.routeAlives=[],this.listeners=[],this.__withRouteListeners=[],this.__redirectListener=d(this),this.setMode(e)}function l(t,e){var r=e.rule,n=[""];if("string"==typeof r){var o=r.replace(/\/:([a-z0-9_-]+)(?=\/|$)/gi,function(t,e){return n.push(e),"/([^/\\s]+)"});r=new RegExp("^"+o+"$","i")}if(!(r instanceof RegExp))throw new Error("[SAN-ROUTER ERROR] Rule must be string or RegExp!");var i=c();t.routes.push({id:i,rule:r,handler:e.handler,keys:n,target:e.target||"#main",Component:e.Component,config:e})}function d(t){return function(e){function n(){if(h>0){if(u<t.listeners.length){t.listeners[u++].call(t,c)}else o();h>0&&n()}}function o(){if(h=-1,s)v(t,s);else for(var e=t.routeAlives.length;e--;)t.routeAlives[e].component.dispose(),t.routeAlives.splice(e,1)}var i=r(e.url),s=t.match(i,e.referrer),a=s?s.data:i,u=0,h=1,c={url:e.url,hash:a.hash,queryString:a.queryString,query:a.query,params:a.params,path:a.path,referrer:e.referrer,config:s&&s.route.config,data:s&&s.data,resume:function(){0===h&&(h=1,n())},suspend:function(){h=0},stop:function(){h=-1}};n()}}function v(t,e){for(var r=e.route,n=!1,o=t.routeAlives.length,i=t.__withRouteListeners.slice(0);o--;){var s=t.routeAlives[o];s.id===r.id?(s.component.data.set("route",e.data),"function"==typeof s.component.route&&s.component.route(),n=!0):(s.component.dispose(),t.routeAlives.splice(o,1))}n||(r.Component?p(r.Component)?y(t,e):r.Component().then(function(n){p(n)?r.Component=n:n.__esModule&&p(n.default)&&(r.Component=n.default),y(t,e)}):r.handler.call(t,e.data));for(var a=0,u=i.length;a<u;a++)i[a](e)}function y(t,r){var n=r.route,o=new n.Component;o.$router=t,o.data.set("route",r.data),"function"==typeof o.route&&o.route();var i=n.target,s=e(i);if(!s)throw new Error('[SAN-ROUTER ERROR] Attach failed, target element "'+n.target+'" is not found.');o.attach(s),t.routeAlives.push({component:o,id:n.id}),"function"==typeof n.handler&&setTimeout(function(){n.handler.call(t,r.data)})}function g(t){var e=new Function;e.prototype=t.prototype;var r=function(e){return t.call(this,e)||this};return r.prototype=new e,r.prototype.constructor=r,e.prototype.hasOwnProperty("aPack")&&(r.prototype.aPack=e.prototype.aPack),r}function m(t){var e;return e=0===t.toString().indexOf("class")?R(t):g(t),e.template=t.template,e.components=t.components,e.trimWhitespace=t.trimWhitespace,e.delimiters=t.delimiters,e.autoFillStyleAndId=t.autoFillStyleAndId,e.filters=t.filters,e.computed=t.computed,e.aPack=t.aPack,e.messages=t.messages,e}function w(t,e){e=e||S;var r,n,o;"function"==typeof t?(n=m(t),r=t.prototype,o=n.prototype):(r=t||{},n=Object.assign({},t),o=n);var i=r.inited;o.inited=function(){this.$router=e,this.data.set("route",e.match(e.locator.current,e.locator.referrer).data),"function"==typeof this.route&&this.route();var t=this;this.__routerListener=function(e){t.data.set("route",e.data),"function"==typeof t.route&&t.route()},e.__withRouteListeners.push(this.__routerListener),"function"==typeof i&&i.call(this)};var s=r.disposed;return o.disposed=function(){if(this.$router){for(var t=this.$router.__withRouteListeners,e=t.length;e--;)if(t[e]===this.__routerListener){t.splice(e,1);break}this.__routerListener=null,this.$router=null}"function"==typeof s&&s.call(this)},n}function L(t){return{template:'<a href="{{hrefPrefix}}{{href}}" onclick="return false;" on-click="clicker($event)" target="{{target}}" class="{{isActive ? activeClass : \'\'}}"><slot/></a>',clicker:function(e){var r=this.data.get("href");"string"==typeof r&&t.locator.redirect(r.replace(/^#/,"")),e.preventDefault?e.preventDefault():e.returnValue=!1},inited:function(){var e=this;this.routeListener=function(t){e.data.set("isActive",t.url===e.data.get("href"))},this.routeListener({url:t.locator.current}),t.listen(this.routeListener)},disposed:function(){t.unlisten(this.routeListener),this.routeListener=null},initData:function(){return{isActive:!1,hrefPrefix:"hash"===t.mode?"#":""}},computed:{href:function(){return o(this.data.get("to")||"",t.locator.current)}}}}i.prototype.on=function(t,e){"function"==typeof e&&(this._eventListeners||(this._eventListeners={}),this._eventListeners[t]||(this._eventListeners[t]=[]),this._eventListeners[t].push(e))},i.prototype.un=function(t,e){if(this._eventListeners&&this._eventListeners[t])if(e)for(var r=this._eventListeners[t],n=r.length;n--;)r[n]===e&&r.splice(n,1);else this._eventListeners[t]=[]},i.prototype.fire=function(t,e){if(!t)throw new Error("No event type specified");var r=this._eventListeners&&this._eventListeners[t];if(r)for(var n=0;n<r.length;n++)r[n](e)},a.prototype=new i,a.prototype.constructor=a,a.prototype.start=function(){window.addEventListener&&window.addEventListener("hashchange",this.hashChangeHandler,!1),window.attachEvent&&window.attachEvent("onhashchange",this.hashChangeHandler)},a.prototype.stop=function(){window.removeEventListener&&window.removeEventListener("hashchange",this.hashChangeHandler,!1),window.detachEvent&&window.detachEvent("onhashchange",this.hashChangeHandler)},a.prototype.redirect=function(t,e){e=e||{},t=o(t,this.current);var r=this.current,n=t!==r;n?(this.referrer=r,this.current=t,location.hash=t):r=this.referrer,!n&&!e.force||e.silent||this.fire("redirect",{url:t,referrer:r})},a.prototype.reload=function(){this.redirect(this.current,{force:!0})},h.prototype=new i,h.prototype.constructor=h,h.prototype.start=function(){window.addEventListener("popstate",this.popstateHandler)},h.prototype.stop=function(){window.removeEventListener("popstate",this.popstateHandler)},h.prototype.redirect=function(t,e){e=e||{},t=o(t,this.current);var r=this.current,n=t!==r;n&&(this.referrer=r,this.current=t,history.pushState({},"",t)),!n&&!e.force||e.silent||this.fire("redirect",{url:t,referrer:r})},h.prototype.reload=function(){this.fire("redirect",{url:this.current,referrer:this.referrer})},h.isSupport="pushState"in window.history;var _=365611;f.prototype.match=function(t,e){"string"==typeof t&&(t=r(t));for(var n=0;n<this.routes.length;n++){var o=this.routes[n],i=o.rule.exec(t.path);if(i){for(var s=o.keys||[],a=1;a<i.length;a++){var u=s[a]||a,h=i[a];t.query[u]=h,t.params[u]=h}return{data:{hash:t.hash,queryString:t.queryString,params:t.params,query:t.query,path:t.path,referrer:e},url:t,route:o}}}return null},f.prototype.listen=function(t){this.listeners.push(t)},f.prototype.unlisten=function(t){for(var e=this.listeners.length;e--;)this.listeners[e]===t&&this.listeners.splice(e,1)},f.prototype.start=function(){return this.isStarted||(this.isStarted=!0,this.locator.on("redirect",this.__redirectListener),this.locator.start(),this.locator.reload()),this},f.prototype.stop=function(){return this.locator.un("redirect",this.__redirectListener),this.locator.stop(),this.isStarted=!1,this},f.prototype.setMode=function(t){if(t=t.toLowerCase(),this.mode!==t){this.mode=t;var e=!1;switch(this.isStarted&&(this.stop(),e=!0),t){case"hash":this.locator=new a;break;case"html5":this.locator=new h}return e&&this.start(),this}},f.prototype.add=function(t){if(t instanceof Array)for(var e=0,r=t.length;e<r;e++)l(this,t[e]);else"object"==typeof t&&l(this,t);return this},f.prototype.push=function(t,e){(t=n(t))&&this.locator.redirect(t,e)};var R,S=new f;try{R=new Function("RawClass","return class extends RawClass {}")}catch(t){}var E={Link:L(S),createLink:L,withRoute:w,router:S,Router:f,HashLocator:a,HTML5Locator:h,resolveURL:o,parseURL:r,stringifyURL:n,version:"2.0.0"};"object"==typeof exports&&"object"==typeof module?exports=module.exports=E:"function"==typeof define&&define.amd?define("san-router",[],E):t.sanRouter=E}(this); |
609
index.js
@@ -6,3 +6,3 @@ /** | ||
(function (root) { | ||
(function (root) { | ||
@@ -104,3 +104,3 @@ /** | ||
} | ||
var query = source.query; | ||
@@ -192,4 +192,4 @@ var params = source.params; | ||
return path + (sourceLoc.queryString ? '?' + sourceLoc.queryString : ''); | ||
@@ -380,2 +380,6 @@ } | ||
function HTML5Locator() { | ||
if (!HTML5Locator.isSupport) { | ||
throw new Error('[SAN-ROUTER ERROR] Your navigator doesn\'t supports HTML5!'); | ||
} | ||
this.current = getLocation(); | ||
@@ -454,4 +458,2 @@ this.referrer = ''; | ||
var routeID = 0x5942b; | ||
@@ -466,116 +468,3 @@ function guid() { | ||
/** | ||
* 获取 router 的 locator redirect 事件监听函数 | ||
* | ||
* @return {Function} | ||
*/ | ||
function getLocatorRedirectHandler(router) { | ||
return function (e) { | ||
var url = parseURL(e.url); | ||
var routeItem; | ||
for (var i = 0; i < router.routes.length; i++) { | ||
var item = router.routes[i]; | ||
var match = item.rule.exec(url.path); | ||
if (match) { | ||
routeItem = item; | ||
// fill params | ||
var keys = item.keys || []; | ||
for (var j = 1; j < match.length; j++) { | ||
var key = keys[j] || j; | ||
var value = match[j]; | ||
url.query[key] = value; | ||
url.params[key] = value; | ||
} | ||
// fill referrer | ||
url.referrer = e.referrer; | ||
url.config = item.config; | ||
break; | ||
} | ||
} | ||
var i = 0; | ||
var state = 1; | ||
/** | ||
* listener 事件对象 | ||
* | ||
* @type {Object} | ||
*/ | ||
var listenerEvent = { | ||
url: e.url, | ||
hash: url.hash, | ||
queryString: url.queryString, | ||
query: url.query, | ||
params: url.params, | ||
path: url.path, | ||
referrer: url.referrer, | ||
config: url.config, | ||
resume: next, | ||
suspend: function () { | ||
state = 0; | ||
}, | ||
stop: function () { | ||
state = -1; | ||
} | ||
}; | ||
/** | ||
* 尝试运行下一个listener | ||
* | ||
* @inner | ||
*/ | ||
function doNext() { | ||
if (state > 0) { | ||
if (i < router.listeners.length) { | ||
router.listeners[i].call(router, listenerEvent, url.config); | ||
if (state > 0) { | ||
next(); | ||
} | ||
} | ||
else { | ||
routeAction(); | ||
} | ||
} | ||
} | ||
/** | ||
* 运行下一个listener | ||
* | ||
* @inner | ||
*/ | ||
function next() { | ||
state = 1; | ||
i++; | ||
doNext(); | ||
} | ||
/** | ||
* 运行路由行为 | ||
* | ||
* @inner | ||
*/ | ||
function routeAction() { | ||
if (routeItem) { | ||
router.doRoute(routeItem, url); | ||
} | ||
else { | ||
var len = router.routeAlives.length; | ||
while (len--) { | ||
router.routeAlives[len].component.dispose(); | ||
router.routeAlives.splice(len, 1); | ||
} | ||
} | ||
}; | ||
doNext(); | ||
}; | ||
} | ||
/** | ||
@@ -592,6 +481,2 @@ * 路由器类 | ||
if (mode === 'html5' && !HTML5Locator.isSupport) { | ||
throw new Error('[SAN-ROUTER ERROR] Your navigator doesn\'t supports HTML5!'); | ||
} | ||
this.routes = []; | ||
@@ -601,4 +486,5 @@ this.routeAlives = []; | ||
this.__withRouteListeners = []; | ||
this.__redirectListener = routerGetRedirectListener(this); | ||
this.locatorRedirectHandler = getLocatorRedirectHandler(this); | ||
this.setMode(mode); | ||
@@ -608,2 +494,45 @@ } | ||
/** | ||
* 匹配 url | ||
* | ||
* @param {Object|string} url 要匹配的url | ||
* @return {Object} routeInfo | ||
*/ | ||
Router.prototype.match = function (url, referrer) { | ||
if (typeof url === 'string') { | ||
url = parseURL(url); | ||
} | ||
for (var i = 0; i < this.routes.length; i++) { | ||
var item = this.routes[i]; | ||
var match = item.rule.exec(url.path); | ||
if (match) { | ||
// fill params | ||
var keys = item.keys || []; | ||
for (var j = 1; j < match.length; j++) { | ||
var key = keys[j] || j; | ||
var value = match[j]; | ||
url.query[key] = value; | ||
url.params[key] = value; | ||
} | ||
return { | ||
data: { | ||
hash: url.hash, | ||
queryString: url.queryString, | ||
params: url.params, | ||
query: url.query, | ||
path: url.path, | ||
referrer: referrer | ||
}, | ||
url: url, | ||
route: item | ||
}; | ||
} | ||
} | ||
return null; | ||
} | ||
/** | ||
* 添加路由监听器 | ||
@@ -639,3 +568,3 @@ * | ||
this.isStarted = true; | ||
this.locator.on('redirect', this.locatorRedirectHandler); | ||
this.locator.on('redirect', this.__redirectListener); | ||
this.locator.start(); | ||
@@ -654,3 +583,3 @@ this.locator.reload(); | ||
Router.prototype.stop = function () { | ||
this.locator.un('redirect', this.locatorRedirectHandler); | ||
this.locator.un('redirect', this.__redirectListener); | ||
this.locator.stop(); | ||
@@ -698,17 +627,183 @@ this.isStarted = false; | ||
/** | ||
* 添加路由项,支持单一数据或者数组配置 | ||
* | ||
* @public | ||
* @param {Object|Array<Object>} config 路由项配置 | ||
* @return {Object} san-router 实例 | ||
*/ | ||
Router.prototype.add = function (config) { | ||
if (config instanceof Array) { | ||
for (var i = 0, l = config.length; i < l; i++) { | ||
routerAdd(this, config[i]); | ||
} | ||
} | ||
else if (typeof config === 'object') { | ||
routerAdd(this, config); | ||
} | ||
return this; | ||
}; | ||
/** | ||
* 编程式路由函数,间接使用 redirect 重定向,避免直接使用内部对象locator | ||
* | ||
* @param {Object|string} url 路由地址 | ||
* @param {Object?} options 重定向的行为配置 | ||
* @param {boolean?} options.force 是否强制刷新 | ||
*/ | ||
Router.prototype.push = function (url, options) { | ||
url = stringifyURL(url); | ||
if (url) { | ||
this.locator.redirect(url, options); | ||
} | ||
}; | ||
/** | ||
* 添加路由项 | ||
* 当规则匹配时,路由将优先将Component渲染到target中。如果没有包含Component,则执行handler函数 | ||
* | ||
* @param {Object} config 路由项配置 | ||
* @param {string|RegExp} config.rule 路由规则 | ||
* @param {Function?} config.handler 路由函数 | ||
* @param {Function?} config.Component 路由组件 | ||
* @param {string} config.target 路由组件要渲染到的目标位置 | ||
*/ | ||
function routerAdd(router, config) { | ||
var rule = config.rule; | ||
var keys = ['']; | ||
if (typeof rule === 'string') { | ||
// 没用path-to-regexp,暂时不提供这么多功能支持 | ||
var regText = rule.replace( | ||
/\/:([a-z0-9_-]+)(?=\/|$)/ig, | ||
function (match, key) { | ||
keys.push(key); | ||
return '/([^/\\s]+)'; | ||
} | ||
); | ||
rule = new RegExp('^' + regText + '$', 'i'); | ||
} | ||
if (!(rule instanceof RegExp)) { | ||
throw new Error('[SAN-ROUTER ERROR] Rule must be string or RegExp!'); | ||
} | ||
var id = guid(); | ||
router.routes.push({ | ||
id: id, | ||
rule: rule, | ||
handler: config.handler, | ||
keys: keys, | ||
target: config.target || '#main', | ||
Component: config.Component, | ||
config: config | ||
}); | ||
} | ||
/** | ||
* 获取 router 的 locator redirect 事件监听函数 | ||
* | ||
* @param {Router} router router 实例 | ||
* @return {Function} | ||
*/ | ||
function routerGetRedirectListener(router) { | ||
return function (e) { | ||
var url = parseURL(e.url); | ||
var routeInfo = router.match(url, e.referrer); | ||
var listenerSource = routeInfo ? routeInfo.data : url; | ||
var i = 0; | ||
var state = 1; | ||
/** | ||
* listener 事件对象 | ||
* | ||
* @type {Object} | ||
*/ | ||
var listenerEvent = { | ||
url: e.url, | ||
hash: listenerSource.hash, | ||
queryString: listenerSource.queryString, | ||
query: listenerSource.query, | ||
params: listenerSource.params, | ||
path: listenerSource.path, | ||
referrer: e.referrer, | ||
config: routeInfo && routeInfo.route.config, | ||
data: routeInfo && routeInfo.data, | ||
resume: function () { | ||
if (state === 0) { | ||
state = 1; | ||
doNext(); | ||
} | ||
}, | ||
suspend: function () { | ||
state = 0; | ||
}, | ||
stop: function () { | ||
state = -1; | ||
} | ||
}; | ||
/** | ||
* 尝试运行下一个listener | ||
* | ||
* @inner | ||
*/ | ||
function doNext() { | ||
if (state > 0) { | ||
if (i < router.listeners.length) { | ||
var listener = router.listeners[i++]; | ||
listener.call(router, listenerEvent); | ||
} | ||
else { | ||
routeAction(); | ||
} | ||
if (state > 0) { | ||
doNext(); | ||
} | ||
} | ||
} | ||
/** | ||
* 运行路由行为 | ||
* | ||
* @inner | ||
*/ | ||
function routeAction() { | ||
state = -1; | ||
if (routeInfo) { | ||
routerDoRoute(router, routeInfo); | ||
} | ||
else { | ||
var len = router.routeAlives.length; | ||
while (len--) { | ||
router.routeAlives[len].component.dispose(); | ||
router.routeAlives.splice(len, 1); | ||
} | ||
} | ||
} | ||
doNext(); | ||
}; | ||
} | ||
/** | ||
* 执行路由 | ||
* | ||
* @private | ||
* @param {Object} routeItem 路由项 | ||
* @param {Object} e 路由信息 | ||
* @param {Object} routeInfo 路由信息 | ||
*/ | ||
Router.prototype.doRoute = function (routeItem, e) { | ||
function routerDoRoute(router, routeInfo) { | ||
var routeItem = routeInfo.route; | ||
var isUpdateAlive = false; | ||
var len = this.routeAlives.length; | ||
var len = router.routeAlives.length; | ||
var withRouteListeners = router.__withRouteListeners.slice(0); | ||
while (len--) { | ||
var routeAlive = this.routeAlives[len]; | ||
var routeAlive = router.routeAlives[len]; | ||
if (routeAlive.id === routeItem.id) { | ||
routeAlive.component.data.set('route', e); | ||
routeAlive.component.data.set('route', routeInfo.data); | ||
if (typeof routeAlive.component.route === 'function') { | ||
@@ -721,39 +816,41 @@ routeAlive.component.route(); | ||
routeAlive.component.dispose(); | ||
this.routeAlives.splice(len, 1); | ||
router.routeAlives.splice(len, 1); | ||
} | ||
} | ||
if (isUpdateAlive) { | ||
return; | ||
} | ||
if (routeItem.Component) { | ||
if (isComponent(routeItem.Component)) { | ||
this.attachCmpt(routeItem, e); | ||
if (!isUpdateAlive) { | ||
if (routeItem.Component) { | ||
if (isComponent(routeItem.Component)) { | ||
routerAttachComponent(router, routeInfo); | ||
} | ||
else { | ||
routeItem.Component().then( | ||
function (Cmpt) { // eslint-disable-line | ||
if (isComponent(Cmpt)) { | ||
routeItem.Component = Cmpt; | ||
} | ||
else if (Cmpt.__esModule && isComponent(Cmpt['default'])) { | ||
routeItem.Component = Cmpt['default']; | ||
} | ||
routerAttachComponent(router, routeInfo); | ||
} | ||
); | ||
} | ||
} | ||
else { | ||
var me = this; | ||
routeItem.Component().then( | ||
function (Cmpt) { // eslint-disable-line | ||
if (isComponent(Cmpt)) { | ||
routeItem.Component = Cmpt; | ||
} | ||
else if (Cmpt.__esModule && isComponent(Cmpt['default'])) { | ||
routeItem.Component = Cmpt['default']; | ||
} | ||
me.attachCmpt(routeItem, e); | ||
} | ||
); | ||
routeItem.handler.call(router, routeInfo.data); | ||
} | ||
} | ||
else { | ||
routeItem.handler.call(this, e); | ||
for (var i = 0, l = withRouteListeners.length; i < l; i++) { | ||
withRouteListeners[i](routeInfo); | ||
} | ||
}; | ||
} | ||
Router.prototype.attachCmpt = function (routeItem, e) { | ||
var me = this; | ||
function routerAttachComponent(router, routeInfo) { | ||
var routeItem = routeInfo.route; | ||
var component = new routeItem.Component(); | ||
component['$router'] = this; | ||
component.data.set('route', e); | ||
component['$router'] = router; | ||
component.data.set('route', routeInfo.data); | ||
if (typeof component.route === 'function') { | ||
@@ -763,3 +860,2 @@ component.route(); | ||
var target = routeItem.target; | ||
@@ -777,3 +873,3 @@ var targetEl = elementSelector(target); | ||
this.routeAlives.push({ | ||
router.routeAlives.push({ | ||
component: component, | ||
@@ -786,75 +882,138 @@ id: routeItem.id | ||
setTimeout(function () { | ||
routeItem.handler.call(me, e); | ||
}) | ||
routeItem.handler.call(router, routeInfo.data); | ||
}); | ||
} | ||
}; | ||
} | ||
/** | ||
* 添加路由项 | ||
* 当规则匹配时,路由将优先将Component渲染到target中。如果没有包含Component,则执行handler函数 | ||
* | ||
* @private | ||
* @param {Object} config 路由项配置 | ||
* @param {string|RegExp} config.rule 路由规则 | ||
* @param {Function?} config.handler 路由函数 | ||
* @param {Function?} config.Component 路由组件 | ||
* @param {string} config.target 路由组件要渲染到的目标位置 | ||
* @return {Object} san-router 实例 | ||
*/ | ||
Router.prototype.add = function (config) { | ||
var rule = config.rule; | ||
var keys = ['']; | ||
if (typeof rule === 'string') { | ||
// 没用path-to-regexp,暂时不提供这么多功能支持 | ||
var regText = rule.replace( | ||
/\/:([a-z0-9_-]+)(?=\/|$)/ig, | ||
function (match, key) { | ||
keys.push(key); | ||
return '/([^/\\s]+)'; | ||
} | ||
); | ||
var router = new Router(); | ||
rule = new RegExp('^' + regText + '$', 'i'); | ||
var extendsAsClass; | ||
try { | ||
extendsAsClass = new Function('RawClass', "return class extends RawClass {}"); | ||
} | ||
catch (ex) {} | ||
function extendsAsFunc(RawClass) { | ||
var F = new Function(); | ||
F.prototype = RawClass.prototype; | ||
var NewClass = function (option) { | ||
return RawClass.call(this, option) || this; | ||
}; | ||
NewClass.prototype = new F(); | ||
NewClass.prototype.constructor = NewClass; | ||
if (F.prototype.hasOwnProperty('aPack')) { | ||
NewClass.prototype.aPack = F.prototype.aPack; | ||
} | ||
if (!(rule instanceof RegExp)) { | ||
throw new Error('[SAN-ROUTER ERROR] Rule must be string or RegExp!'); | ||
return NewClass; | ||
} | ||
function extendsComponent(ComponentClass) { | ||
var NewComponentClass; | ||
if (ComponentClass.toString().indexOf('class') === 0) { | ||
NewComponentClass = extendsAsClass(ComponentClass); | ||
} | ||
else { | ||
NewComponentClass = extendsAsFunc(ComponentClass); | ||
} | ||
var id = guid(); | ||
this.routes.push({ | ||
id: id, | ||
rule: rule, | ||
handler: config.handler, | ||
keys: keys, | ||
target: config.target || '#main', | ||
Component: config.Component, | ||
config: config | ||
}); | ||
NewComponentClass.template = ComponentClass.template; | ||
NewComponentClass.components = ComponentClass.components; | ||
NewComponentClass.trimWhitespace = ComponentClass.trimWhitespace; | ||
NewComponentClass.delimiters = ComponentClass.delimiters; | ||
NewComponentClass.autoFillStyleAndId = ComponentClass.autoFillStyleAndId; | ||
NewComponentClass.filters = ComponentClass.filters; | ||
NewComponentClass.computed = ComponentClass.computed; | ||
NewComponentClass.aPack = ComponentClass.aPack; | ||
NewComponentClass.messages = ComponentClass.messages; | ||
return this; | ||
}; | ||
return NewComponentClass; | ||
} | ||
/** | ||
* 编程式路由函数,间接使用 redirect 重定向,避免直接使用内部对象locator | ||
* 为组件生成支持路由关联的高阶组件 | ||
* | ||
* @param {Object|string} url 路由地址 | ||
* @param {Object?} options 重定向的行为配置 | ||
* @param {boolean?} options.force 是否强制刷新 | ||
* @param {Function|Class} ComponentClass 组件类 | ||
* @param {Router?} customRouter 关联的 router 实例 | ||
* @returns 高阶组件 | ||
*/ | ||
Router.prototype.push = function (url, options) { | ||
url = stringifyURL(url); | ||
if (url) { | ||
this.locator.redirect(url, options); | ||
function withRoute(ComponentClass, customRouter) { | ||
customRouter = customRouter || router; | ||
var componentProto; | ||
var ReturnTarget; | ||
var extProto; | ||
if (typeof ComponentClass === 'function') { | ||
ReturnTarget = extendsComponent(ComponentClass); | ||
componentProto = ComponentClass.prototype; | ||
extProto = ReturnTarget.prototype; | ||
} | ||
else { | ||
componentProto = ComponentClass || {}; | ||
ReturnTarget = Object.assign({}, ComponentClass); | ||
extProto = ReturnTarget; | ||
} | ||
// 注入 $router 以及 data route | ||
var inited = componentProto.inited; | ||
extProto.inited = function () { | ||
this.$router = customRouter; | ||
this.data.set( | ||
'route', | ||
customRouter.match( | ||
customRouter.locator.current, | ||
customRouter.locator.referrer | ||
).data | ||
); | ||
if (typeof this.route === 'function') { | ||
this.route(); | ||
} | ||
// 路由信息实时获取 | ||
var me = this; | ||
this.__routerListener = function (e) { | ||
me.data.set('route', e.data); | ||
if (typeof me.route === 'function') { | ||
me.route(); | ||
} | ||
}; | ||
customRouter.__withRouteListeners.push(this.__routerListener); | ||
if (typeof inited === 'function') { | ||
inited.call(this); | ||
} | ||
}; | ||
// dispose 监听器 | ||
var disposed = componentProto.disposed; | ||
extProto.disposed = function () { | ||
if (this.$router) { | ||
// unlisten from router | ||
var listeners = this.$router.__withRouteListeners; | ||
var len = listeners.length; | ||
while (len--) { | ||
if (listeners[len] === this.__routerListener) { | ||
listeners.splice(len, 1); | ||
break; | ||
} | ||
} | ||
this.__routerListener = null; | ||
this.$router = null; | ||
} | ||
if (typeof disposed === 'function') { | ||
disposed.call(this); | ||
} | ||
}; | ||
return ReturnTarget; | ||
} | ||
var router = new Router(); | ||
var main = { | ||
/** | ||
* 路由链接的 San 组件 | ||
*/ | ||
Link: { | ||
function createLink(router) { | ||
return { | ||
template: '<a href="{{hrefPrefix}}{{href}}" onclick="return false;" on-click="clicker($event)" ' | ||
@@ -906,4 +1065,9 @@ + 'target="{{target}}" class="{{isActive ? activeClass : \'\'}}"><slot/></a>', | ||
} | ||
}, | ||
}; | ||
} | ||
var main = { | ||
Link: createLink(router), | ||
createLink: createLink, | ||
withRoute: withRoute, | ||
router: router, | ||
@@ -917,6 +1081,6 @@ Router: Router, | ||
version: '1.2.4' | ||
version: '2.0.0' | ||
}; | ||
if (typeof exports === 'object' && typeof module === 'object') { | ||
@@ -934,3 +1098,2 @@ // For CommonJS | ||
})(this); | ||
})(this); |
{ | ||
"name": "san-router", | ||
"version": "1.2.4", | ||
"version": "2.0.0", | ||
"description": "Router for San", | ||
"scripts": { | ||
"pretest": "npm run build && http-server ./ &", | ||
"test": "open http://127.0.0.1:8080/test/", | ||
"build": "rm -rf dist && mkdir dist && uglifyjs index.js -mco dist/san-router.js" | ||
"pretest": "npm run build", | ||
"test": "http-server -c-1 -o /test", | ||
"build": "rm -rf dist && mkdir dist && uglifyjs index.js -mco dist/san-router.js", | ||
"docs:start": "docusaurus start --config ./website/docusaurus.config.js", | ||
"docs:build": "docusaurus build --config ./website/docusaurus.config.js" | ||
}, | ||
"devDependencies": { | ||
"@docusaurus/core": "^2.0.0-beta.18", | ||
"@docusaurus/preset-classic": "^2.0.0-beta.18", | ||
"http-server": "^0.12.3", | ||
"jasmine-core": "^2.99.1", | ||
"san": "^3.4.2", | ||
"react": "^17.0.2", | ||
"react-dom": "^17.0.2", | ||
"san": "^3.11.2", | ||
"uglify-js": "^2.7.5" | ||
@@ -24,3 +30,2 @@ }, | ||
"types": "types", | ||
"dependencies": {}, | ||
"author": "otakustay", | ||
@@ -27,0 +32,0 @@ "repository": { |
281
README.md
@@ -6,278 +6,47 @@ # san-router | ||
[San](https://baidu.github.io/san/) 框架的官方 router。通常,单页或同构的 Web 应用都会需要一个 router。 | ||
[San](https://baidu.github.io/san/) 框架的官方 router,支持动态路由,嵌套路由,路由懒加载以及导航守卫等功能。 | ||
你可以从下面找到 san-router 的下载和使用说明,也可以直接从 [示例项目](https://github.com/baidu/san/tree/master/example/todos-esnext) 看看实际项目中的使用方法。 | ||
> 注意:使用 san-router,要求 San 的版本号 >= 3.0.2 | ||
[文档](https://baidu.github.io/san-router/) | [示例项目](https://github.com/baidu/san/tree/master/example/todos-esnext) | ||
下载 | ||
---- | ||
## 下载 | ||
NPM: | ||
``` | ||
$ npm i san-router | ||
# use npm | ||
npm i san-router | ||
# or use yarn | ||
yarn add san-router | ||
``` | ||
## 使用 | ||
使用 | ||
---- | ||
如需了解更多功能,请访问 [快速开始](https://baidu.github.io/san-router/docs/quick-start) | ||
### Webpack + Babel | ||
通过 named import 导入 | ||
```javascript | ||
``` | ||
import {router, Link} from 'san-router'; | ||
router.add({ | ||
rule: '/book/:id', | ||
rule: '/book', | ||
Component: BookDetail | ||
}); | ||
router.add([ | ||
{ | ||
rule: '/about', | ||
Component: About | ||
}, | ||
{ | ||
rule: '/home', | ||
Component: Home | ||
} | ||
]); | ||
router.start(); | ||
``` | ||
webpack 环境配置网上有太多文章,在此不赘述了 | ||
## CHANGELOG | ||
[CHANGELOG](https://github.com/baidu/san-router/blob/master/CHANGELOG.md) | ||
### AMD | ||
## License | ||
通过 require 拿到的 exports 上包含 router 和 Link | ||
```javascript | ||
var sanRouter = require('san-router'); | ||
var router = sanRouter.router; | ||
var Link = sanRouter.Link; | ||
router.add({ | ||
rule: '/book/:id', | ||
Component: BookDetail | ||
}); | ||
router.start(); | ||
``` | ||
请为 amd loader 正确配置 san-router 的引用路径。通过 npm 安装的项目可以采用下面的配置 | ||
```javascript | ||
require.config({ | ||
baseUrl: 'src', | ||
paths: { | ||
'san-router': '../dep/san-router/dist/san-router.source' | ||
} | ||
}); | ||
``` | ||
API | ||
---- | ||
### router | ||
路由器对象。 | ||
路由用于将特定的 URL 对应到组件类上。在 URL 变化并匹配路由规则时,路由将初始化特定组件并渲染到页面上。你也可以将 URL 对应到函数上,路由将在 URL 规则匹配时执行特定函数。 | ||
#### add({Object}options) | ||
`说明` | ||
添加一条路由规则。 | ||
你可以指定 Component 和 target 参数,让规则匹配时在 target 中渲染一个 Component。 | ||
```javascript | ||
router.add({ | ||
rule: '/book/:id', | ||
Component: san.defineComponent({ | ||
route() { | ||
let route = this.data.get('route'); | ||
// route.query.id | ||
} | ||
}), | ||
target: '.app-main' | ||
}); | ||
``` | ||
Component 属性也可以用来加载一个异步的组件: | ||
```js | ||
const BookComponent = () => import('./BookComponent'); | ||
router.add({ | ||
rule: '/book/:id', | ||
Component: BookComponent, | ||
target: '.app-main' | ||
}); | ||
``` | ||
你也可以指定一个 handler 函数,让规则匹配时执行这个函数。 | ||
```javascript | ||
router.add({ | ||
rule: '/book/:id', | ||
handler(e) { | ||
e.query.id | ||
} | ||
}); | ||
``` | ||
路由规则有2种形式: | ||
- `string` URL 的 path 部分与字符串完全匹配。支持 `:` 标记的路径参数,根据名称作为 query 的参数传递给相应的组件或函数。 | ||
- `RegExp` URL 的 path 部分匹配该正则。正则中的 group 将根据序号作为 query 的参数传递给相应的组件或函数。 | ||
`参数` | ||
- `string|RegExp` options.rule - 路由规则 | ||
- `Function` options.Component - 规则匹配时渲染的组件类 | ||
- `string` options.target - 组件渲染的容器元素,默认值为 **#main** | ||
- `Function` options.handler 规则匹配时的执行函数 | ||
#### listen({Function}listener) | ||
`说明` | ||
添加路由监听器。当发生路由行为时,监听器函数被触发。 | ||
```javascript | ||
router.listen(function (e, config) { | ||
e.query.id | ||
}); | ||
``` | ||
`参数` | ||
- `Function` listener - 监听器函数 | ||
`监听器函数参数` | ||
- `Object` e - 路由信息对象 | ||
- `Object` config - 路由配置对象 | ||
路由监听器作为所有路由的切面函数,通常承担权限判断之类基础的任务。所以路由监听器可以通过 `stop` 方法阻断当前路由过程,并进行 URL 跳转。 | ||
```javascript | ||
router.listen(function (e) { | ||
if (!checkPermission()) { | ||
e.stop(); | ||
this.locator.redirect('/forbidden'); | ||
} | ||
}); | ||
``` | ||
路由监听器可以通过 `suspend` 和 `resume` 方法中断和唤醒路由过程,实现异步。不过异步过程会导致路由对应的视图渲染延迟,慎用。 | ||
```javascript | ||
router.listen(function (e) { | ||
e.suspend(); | ||
checkPermission().then(invalid => { | ||
if (invalid) { | ||
e.stop(); | ||
this.locator.redirect('/forbidden'); | ||
return; | ||
} | ||
e.resume(); | ||
}); | ||
}); | ||
``` | ||
#### unlisten({Function}listener) | ||
`说明` | ||
移除路由监听器。 | ||
`参数` | ||
- `Function` listener - 监听器函数 | ||
#### setMode({string}mode) | ||
`说明` | ||
设置路由模式。支持两种模式:hash | html5,默认为 hash。 | ||
`参数` | ||
- `string` mode - 路由模式,hash | html5 | ||
### push({Object}url[,{Object}options]) | ||
`说明` | ||
功能类似 router.locator.redict 方法,并增加了 query 对象的处理。同时在 san 组件中可通过实例的 `$router` 方法访问当前路由实例 | ||
```js | ||
router.push({ | ||
query: { | ||
name: 'erik', | ||
sex: 1, | ||
age: 18 | ||
} | ||
}); | ||
// san 组件中 | ||
this.$router.push({ | ||
query: { | ||
name: 'erik', | ||
sex: 1, | ||
age: 18 | ||
} | ||
}); | ||
``` | ||
#### start() | ||
`说明` | ||
启动路由 | ||
#### stop() | ||
`说明` | ||
停止路由 | ||
### Link | ||
具有路由功能的应用中,建议使用 Link 组件代替 a 标签。Link 组件可以根据路由模式渲染一个链接。通过 to 属性指定目标地址,Link 组件将渲染一个带有正确地址的 a 标签。 | ||
```javascript | ||
san.defineComponent({ | ||
components: { | ||
'router-link': Link | ||
}, | ||
template: ` | ||
<div> | ||
<header> | ||
<router-link to="/user">用户信息</router-link> | ||
</header> | ||
</div> | ||
` | ||
}); | ||
``` | ||
## ChangeLogs | ||
### 1.2.4 | ||
- [feature] `router` 增加 `push` 方法 | ||
- [feature] 在 san 组件中通过 `this.$router` 可以访问 router 实例 | ||
- [fix] 修复 HashLocator 原型指向问题 | ||
### 1.2.3 | ||
- [fix] 修复在 san 3.10.2 版本不支持 callHook 的问题,不再依赖此实现。 | ||
san-router is [MIT licensed](./LICENSE). |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
45549
1001
8
52
1