diff --git a/CHANGELOG.md b/CHANGELOG.md index a0f50df49..c25e2ffb6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,14 @@ +## [3.1.3](https://github.com/vuejs/vue-router/compare/v3.1.2...v3.1.3) (2019-08-30) + +### Bug Fixes + +- **link:** merge event listeners when provided in an anchor ([e0d4dc4](https://github.com/vuejs/vue-router/commit/e0d4dc4)), closes [#2890](https://github.com/vuejs/vue-router/issues/2890) + +### Features + +- **errors:** add stack trace to NavigationDuplicated ([5ef5d73](https://github.com/vuejs/vue-router/commit/5ef5d73)), closes [#2881](https://github.com/vuejs/vue-router/issues/2881) +- warn about root paths without a leading slash ([#2591](https://github.com/vuejs/vue-router/issues/2591)) ([7d7e048](https://github.com/vuejs/vue-router/commit/7d7e048)), closes [#2550](https://github.com/vuejs/vue-router/issues/2550) [#2550](https://github.com/vuejs/vue-router/issues/2550) + ## [3.1.2](https://github.com/vuejs/vue-router/compare/v3.1.1...v3.1.2) (2019-08-08) ### Bug Fixes diff --git a/dist/vue-router.common.js b/dist/vue-router.common.js index 4825f4c15..268584774 100644 --- a/dist/vue-router.common.js +++ b/dist/vue-router.common.js @@ -1,6 +1,6 @@ /*! - * vue-router v3.1.3 - * (c) 2019 Evan You + * vue-router v3.1.4 + * (c) 2020 Evan You * @license MIT */ 'use strict'; @@ -924,7 +924,8 @@ function fillParams ( return filler(params, { pretty: true }) } catch (e) { if (process.env.NODE_ENV !== 'production') { - warn(false, ("missing param for " + routeMsg + ": " + (e.message))); + // Fix #3072 no warn if `pathMatch` is string + warn(typeof params.pathMatch === 'string', ("missing param for " + routeMsg + ": " + (e.message))); } return '' } finally { @@ -946,20 +947,25 @@ function normalizeLocation ( if (next._normalized) { return next } else if (next.name) { - return extend({}, raw) + next = extend({}, raw); + var params = next.params; + if (params && typeof params === 'object') { + next.params = extend({}, params); + } + return next } // relative params if (!next.path && next.params && current) { next = extend({}, next); next._normalized = true; - var params = extend(extend({}, current.params), next.params); + var params$1 = extend(extend({}, current.params), next.params); if (current.name) { next.name = current.name; - next.params = params; + next.params = params$1; } else if (current.matched.length) { var rawPath = current.matched[current.matched.length - 1].path; - next.path = fillParams(rawPath, params, ("path " + (current.path))); + next.path = fillParams(rawPath, params$1, ("path " + (current.path))); } else if (process.env.NODE_ENV !== 'production') { warn(false, "relative params navigation requires a current route."); } @@ -1099,7 +1105,7 @@ var Link = { if (process.env.NODE_ENV !== 'production') { warn( false, - ("RouterLink with to=\"" + (this.props.to) + "\" is trying to use a scoped slot but it didn't provide exactly one child.") + ("RouterLink with to=\"" + (this.to) + "\" is trying to use a scoped slot but it didn't provide exactly one child. Wrapping the content with a span element.") ); } return scopedSlot.length === 0 ? h() : h('span', {}, scopedSlot) @@ -1824,7 +1830,10 @@ function pushState (url, replace) { var history = window.history; try { if (replace) { - history.replaceState({ key: getStateKey() }, '', url); + // preserve existing history state as it could be overriden by the user + var stateCopy = extend({}, history.state); + stateCopy.key = getStateKey(); + history.replaceState(stateCopy, '', url); } else { history.pushState({ key: setStateKey(genStateKey()) }, '', url); } @@ -2539,9 +2548,7 @@ function getHash () { href = decodeURI(href.slice(0, hashIndex)) + href.slice(hashIndex); } else { href = decodeURI(href); } } else { - if (searchIndex > -1) { - href = decodeURI(href.slice(0, searchIndex)) + href.slice(searchIndex); - } + href = decodeURI(href.slice(0, searchIndex)) + href.slice(searchIndex); } return href @@ -2875,7 +2882,7 @@ function createHref (base, fullPath, mode) { } VueRouter.install = install; -VueRouter.version = '3.1.3'; +VueRouter.version = '3.1.4'; if (inBrowser && window.Vue) { window.Vue.use(VueRouter); diff --git a/dist/vue-router.esm.browser.js b/dist/vue-router.esm.browser.js index 4bb357299..f68a0e0ff 100644 --- a/dist/vue-router.esm.browser.js +++ b/dist/vue-router.esm.browser.js @@ -1,6 +1,6 @@ /*! - * vue-router v3.1.3 - * (c) 2019 Evan You + * vue-router v3.1.4 + * (c) 2020 Evan You * @license MIT */ /* */ @@ -908,7 +908,8 @@ function fillParams ( return filler(params, { pretty: true }) } catch (e) { { - warn(false, `missing param for ${routeMsg}: ${e.message}`); + // Fix #3072 no warn if `pathMatch` is string + warn(typeof params.pathMatch === 'string', `missing param for ${routeMsg}: ${e.message}`); } return '' } finally { @@ -930,7 +931,12 @@ function normalizeLocation ( if (next._normalized) { return next } else if (next.name) { - return extend({}, raw) + next = extend({}, raw); + const params = next.params; + if (params && typeof params === 'object') { + next.params = extend({}, params); + } + return next } // relative params @@ -1079,8 +1085,8 @@ var Link = { warn( false, `RouterLink with to="${ - this.props.to - }" is trying to use a scoped slot but it didn't provide exactly one child.` + this.to + }" is trying to use a scoped slot but it didn't provide exactly one child. Wrapping the content with a span element.` ); } return scopedSlot.length === 0 ? h() : h('span', {}, scopedSlot) @@ -1800,7 +1806,10 @@ function pushState (url, replace) { const history = window.history; try { if (replace) { - history.replaceState({ key: getStateKey() }, '', url); + // preserve existing history state as it could be overriden by the user + const stateCopy = extend({}, history.state); + stateCopy.key = getStateKey(); + history.replaceState(stateCopy, '', url); } else { history.pushState({ key: setStateKey(genStateKey()) }, '', url); } @@ -2492,9 +2501,7 @@ function getHash () { href = decodeURI(href.slice(0, hashIndex)) + href.slice(hashIndex); } else href = decodeURI(href); } else { - if (searchIndex > -1) { - href = decodeURI(href.slice(0, searchIndex)) + href.slice(searchIndex); - } + href = decodeURI(href.slice(0, searchIndex)) + href.slice(searchIndex); } return href @@ -2825,7 +2832,7 @@ function createHref (base, fullPath, mode) { } VueRouter.install = install; -VueRouter.version = '3.1.3'; +VueRouter.version = '3.1.4'; if (inBrowser && window.Vue) { window.Vue.use(VueRouter); diff --git a/dist/vue-router.esm.browser.min.js b/dist/vue-router.esm.browser.min.js index c681a911b..e9269a193 100644 --- a/dist/vue-router.esm.browser.min.js +++ b/dist/vue-router.esm.browser.min.js @@ -1,6 +1,6 @@ /*! - * vue-router v3.1.3 - * (c) 2019 Evan You + * vue-router v3.1.4 + * (c) 2020 Evan You * @license MIT */ -function t(t){return Object.prototype.toString.call(t).indexOf("Error")>-1}function e(t,e){return e instanceof t||e&&(e.name===t.name||e._name===t._name)}function n(t,e){for(const n in e)t[n]=e[n];return t}var r={name:"RouterView",functional:!0,props:{name:{type:String,default:"default"}},render(t,{props:e,children:r,parent:o,data:i}){i.routerView=!0;const s=o.$createElement,a=e.name,c=o.$route,u=o._routerViewCache||(o._routerViewCache={});let h=0,p=!1;for(;o&&o._routerRoot!==o;){const t=o.$vnode&&o.$vnode.data;t&&(t.routerView&&h++,t.keepAlive&&o._inactive&&(p=!0)),o=o.$parent}if(i.routerViewDepth=h,p)return s(u[a],i,r);const l=c.matched[h];if(!l)return u[a]=null,s();const f=u[a]=l.components[a];i.registerRouteInstance=(t,e)=>{const n=l.instances[a];(e&&n!==t||!e&&n===t)&&(l.instances[a]=e)},(i.hook||(i.hook={})).prepatch=(t,e)=>{l.instances[a]=e.componentInstance},i.hook.init=t=>{t.data.keepAlive&&t.componentInstance&&t.componentInstance!==l.instances[a]&&(l.instances[a]=t.componentInstance)};let d=i.props=function(t,e){switch(typeof e){case"undefined":return;case"object":return e;case"function":return e(t);case"boolean":return e?t.params:void 0}}(c,l.props&&l.props[a]);if(d){d=i.props=n({},d);const t=i.attrs=i.attrs||{};for(const e in d)f.props&&e in f.props||(t[e]=d[e],delete d[e])}return s(f,i,r)}};const o=/[!'()*]/g,i=t=>"%"+t.charCodeAt(0).toString(16),s=/%2C/g,a=t=>encodeURIComponent(t).replace(o,i).replace(s,","),c=decodeURIComponent;function u(t){const e={};return(t=t.trim().replace(/^(\?|#|&)/,""))?(t.split("&").forEach(t=>{const n=t.replace(/\+/g," ").split("="),r=c(n.shift()),o=n.length>0?c(n.join("=")):null;void 0===e[r]?e[r]=o:Array.isArray(e[r])?e[r].push(o):e[r]=[e[r],o]}),e):e}function h(t){const e=t?Object.keys(t).map(e=>{const n=t[e];if(void 0===n)return"";if(null===n)return a(e);if(Array.isArray(n)){const t=[];return n.forEach(n=>{void 0!==n&&(null===n?t.push(a(e)):t.push(a(e)+"="+a(n)))}),t.join("&")}return a(e)+"="+a(n)}).filter(t=>t.length>0).join("&"):null;return e?`?${e}`:""}const p=/\/?$/;function l(t,e,n,r){const o=r&&r.options.stringifyQuery;let i=e.query||{};try{i=f(i)}catch(t){}const s={name:e.name||t&&t.name,meta:t&&t.meta||{},path:e.path||"/",hash:e.hash||"",query:i,params:e.params||{},fullPath:m(e,o),matched:t?y(t):[]};return n&&(s.redirectedFrom=m(n,o)),Object.freeze(s)}function f(t){if(Array.isArray(t))return t.map(f);if(t&&"object"==typeof t){const e={};for(const n in t)e[n]=f(t[n]);return e}return t}const d=l(null,{path:"/"});function y(t){const e=[];for(;t;)e.unshift(t),t=t.parent;return e}function m({path:t,query:e={},hash:n=""},r){return(t||"/")+(r||h)(e)+n}function g(t,e){return e===d?t===e:!!e&&(t.path&&e.path?t.path.replace(p,"")===e.path.replace(p,"")&&t.hash===e.hash&&w(t.query,e.query):!(!t.name||!e.name)&&(t.name===e.name&&t.hash===e.hash&&w(t.query,e.query)&&w(t.params,e.params)))}function w(t={},e={}){if(!t||!e)return t===e;const n=Object.keys(t),r=Object.keys(e);return n.length===r.length&&n.every(n=>{const r=t[n],o=e[n];return"object"==typeof r&&"object"==typeof o?w(r,o):String(r)===String(o)})}function b(t,e,n){const r=t.charAt(0);if("/"===r)return t;if("?"===r||"#"===r)return e+t;const o=e.split("/");n&&o[o.length-1]||o.pop();const i=t.replace(/^\//,"").split("/");for(let t=0;t=0&&(e=t.slice(r),t=t.slice(0,r));const o=t.indexOf("?");return o>=0&&(n=t.slice(o+1),t=t.slice(0,o)),{path:t,query:n,hash:e}}(i.path||""),a=e&&e.path||"/",c=s.path?b(s.path,a,r||i.append):a,h=function(t,e={},n){const r=n||u;let o;try{o=r(t||"")}catch(t){o={}}for(const t in e)o[t]=e[t];return o}(s.query,i.query,o&&o.options.parseQuery);let p=i.hash||s.hash;return p&&"#"!==p.charAt(0)&&(p=`#${p}`),{_normalized:!0,path:c,query:h,hash:p}}const V=[String,Object],H=[String,Array],z=()=>{};var D={name:"RouterLink",props:{to:{type:V,required:!0},tag:{type:String,default:"a"},exact:Boolean,append:Boolean,replace:Boolean,activeClass:String,exactActiveClass:String,event:{type:H,default:"click"}},render(t){const e=this.$router,r=this.$route,{location:o,route:i,href:s}=e.resolve(this.to,r,this.append),a={},c=e.options.linkActiveClass,u=e.options.linkExactActiveClass,h=null==c?"router-link-active":c,f=null==u?"router-link-exact-active":u,d=null==this.activeClass?h:this.activeClass,y=null==this.exactActiveClass?f:this.exactActiveClass,m=i.redirectedFrom?l(null,B(i.redirectedFrom),null,e):i;a[y]=g(r,m),a[d]=this.exact?a[y]:function(t,e){return 0===t.path.replace(p,"/").indexOf(e.path.replace(p,"/"))&&(!e.hash||t.hash===e.hash)&&function(t,e){for(const n in e)if(!(n in t))return!1;return!0}(t.query,e.query)}(r,m);const w=t=>{F(t)&&(this.replace?e.replace(o,z):e.push(o,z))},b={click:F};Array.isArray(this.event)?this.event.forEach(t=>{b[t]=w}):b[this.event]=w;const v={class:a},x=!this.$scopedSlots.$hasNormal&&this.$scopedSlots.default&&this.$scopedSlots.default({href:s,route:i,navigate:w,isActive:a[d],isExactActive:a[y]});if(x){if(1===x.length)return x[0];if(x.length>1||!x.length)return 0===x.length?t():t("span",{},x)}if("a"===this.tag)v.on=b,v.attrs={href:s};else{const t=function t(e){if(e){let n;for(let r=0;r{!function t(e,n,r,o,i,s){const{path:a,name:c}=o;const u=o.pathToRegexpOptions||{};const h=function(t,e,n){n||(t=t.replace(/\/$/,""));return"/"===t[0]?t:null==e?t:v(`${e.path}/${t}`)}(a,i,u.strict);"boolean"==typeof o.caseSensitive&&(u.sensitive=o.caseSensitive);const p={path:h,regex:Q(h,u),components:o.components||{default:o.component},instances:{},name:c,parent:i,matchAs:s,redirect:o.redirect,beforeEnter:o.beforeEnter,meta:o.meta||{},props:null==o.props?{}:o.components?o.props:{default:o.props}};o.children&&o.children.forEach(o=>{const i=s?v(`${s}/${o.path}`):void 0;t(e,n,r,o,p,i)});n[p.path]||(e.push(p.path),n[p.path]=p);if(void 0!==o.alias){const s=Array.isArray(o.alias)?o.alias:[o.alias];for(let a=0;a!t.optional).map(t=>t.name);if("object"!=typeof c.params&&(c.params={}),i&&"object"==typeof i.params)for(const t in i.params)!(t in c.params)&&e.indexOf(t)>-1&&(c.params[t]=i.params[t]);return c.path=M(t.path,c.params),a(t,c,s)}if(c.path){c.params={};for(let t=0;t{it(),t.state&&t.state.key&&et(t.state.key)})}function ot(t,e,n,r){if(!t.app)return;const o=t.options.scrollBehavior;o&&t.app.$nextTick(()=>{const i=function(){const t=tt();if(t)return nt[t]}(),s=o.call(t,e,n,r?i:null);s&&("function"==typeof s.then?s.then(t=>{ht(t,i)}).catch(t=>{}):ht(s,i))})}function it(){const t=tt();t&&(nt[t]={x:window.pageXOffset,y:window.pageYOffset})}function st(t){return ct(t.x)||ct(t.y)}function at(t){return{x:ct(t.x)?t.x:window.pageXOffset,y:ct(t.y)?t.y:window.pageYOffset}}function ct(t){return"number"==typeof t}const ut=/^#\d/;function ht(t,e){const n="object"==typeof t;if(n&&"string"==typeof t.selector){const n=ut.test(t.selector)?document.getElementById(t.selector.slice(1)):document.querySelector(t.selector);if(n){let o=t.offset&&"object"==typeof t.offset?t.offset:{};e=function(t,e){const n=document.documentElement.getBoundingClientRect(),r=t.getBoundingClientRect();return{x:r.left-n.left-e.x,y:r.top-n.top-e.y}}(n,o={x:ct((r=o).x)?r.x:0,y:ct(r.y)?r.y:0})}else st(t)&&(e=at(t))}else n&&st(t)&&(e=at(t));var r;e&&window.scrollTo(e.x,e.y)}const pt=K&&function(){const t=window.navigator.userAgent;return(-1===t.indexOf("Android 2.")&&-1===t.indexOf("Android 4.0")||-1===t.indexOf("Mobile Safari")||-1!==t.indexOf("Chrome")||-1!==t.indexOf("Windows Phone"))&&(window.history&&"pushState"in window.history)}();function lt(t,e){it();const n=window.history;try{e?n.replaceState({key:tt()},"",t):n.pushState({key:et(G())},"",t)}catch(n){window.location[e?"replace":"assign"](t)}}function ft(t){lt(t,!0)}function dt(t,e,n){const r=o=>{o>=t.length?n():t[o]?e(t[o],()=>{r(o+1)}):r(o+1)};r(0)}function yt(e){return(n,r,o)=>{let i=!1,s=0,a=null;mt(e,(e,n,r,c)=>{if("function"==typeof e&&void 0===e.cid){i=!0,s++;const n=bt(t=>{(function(t){return t.__esModule||wt&&"Module"===t[Symbol.toStringTag]})(t)&&(t=t.default),e.resolved="function"==typeof t?t:N.extend(t),r.components[c]=t,--s<=0&&o()}),u=bt(e=>{const n=`Failed to resolve async component ${c}: ${e}`;a||(a=t(e)?e:new Error(n),o(a))});let h;try{h=e(n,u)}catch(t){u(t)}if(h)if("function"==typeof h.then)h.then(n,u);else{const t=h.component;t&&"function"==typeof t.then&&t.then(n,u)}}}),i||o()}}function mt(t,e){return gt(t.map(t=>Object.keys(t.components).map(n=>e(t.components[n],t.instances[n],t,n))))}function gt(t){return Array.prototype.concat.apply([],t)}const wt="function"==typeof Symbol&&"symbol"==typeof Symbol.toStringTag;function bt(t){let e=!1;return function(...n){if(!e)return e=!0,t.apply(this,n)}}class vt extends Error{constructor(t){super(),this.name=this._name="NavigationDuplicated",this.message=`Navigating to current location ("${t.fullPath}") is not allowed`,Object.defineProperty(this,"stack",{value:(new Error).stack,writable:!0,configurable:!0})}}vt._name="NavigationDuplicated";class xt{constructor(t,e){this.router=t,this.base=function(t){if(!t)if(K){const e=document.querySelector("base");t=(t=e&&e.getAttribute("href")||"/").replace(/^https?:\/\/[^\/]+/,"")}else t="/";"/"!==t.charAt(0)&&(t="/"+t);return t.replace(/\/$/,"")}(e),this.current=d,this.pending=null,this.ready=!1,this.readyCbs=[],this.readyErrorCbs=[],this.errorCbs=[]}listen(t){this.cb=t}onReady(t,e){this.ready?t():(this.readyCbs.push(t),e&&this.readyErrorCbs.push(e))}onError(t){this.errorCbs.push(t)}transitionTo(t,e,n){const r=this.router.match(t,this.current);this.confirmTransition(r,()=>{this.updateRoute(r),e&&e(r),this.ensureURL(),this.ready||(this.ready=!0,this.readyCbs.forEach(t=>{t(r)}))},t=>{n&&n(t),t&&!this.ready&&(this.ready=!0,this.readyErrorCbs.forEach(e=>{e(t)}))})}confirmTransition(n,r,o){const i=this.current,s=n=>{!e(vt,n)&&t(n)&&(this.errorCbs.length?this.errorCbs.forEach(t=>{t(n)}):console.error(n)),o&&o(n)};if(g(n,i)&&n.matched.length===i.matched.length)return this.ensureURL(),s(new vt(n));const{updated:a,deactivated:c,activated:u}=function(t,e){let n;const r=Math.max(t.length,e.length);for(n=0;nt.beforeEnter),yt(u));this.pending=n;const p=(e,r)=>{if(this.pending!==n)return s();try{e(n,i,e=>{!1===e||t(e)?(this.ensureURL(!0),s(e)):"string"==typeof e||"object"==typeof e&&("string"==typeof e.path||"string"==typeof e.name)?(s(),"object"==typeof e&&e.replace?this.replace(e):this.push(e)):r(e)})}catch(t){s(t)}};dt(h,p,()=>{const t=[];dt(function(t,e,n){return kt(t,"beforeRouteEnter",(t,r,o,i)=>(function(t,e,n,r,o){return function(i,s,a){return t(i,s,t=>{"function"==typeof t&&r.push(()=>{!function t(e,n,r,o){n[r]&&!n[r]._isBeingDestroyed?e(n[r]):o()&&setTimeout(()=>{t(e,n,r,o)},16)}(t,e.instances,n,o)}),a(t)})}})(t,o,i,e,n))}(u,t,()=>this.current===n).concat(this.router.resolveHooks),p,()=>{if(this.pending!==n)return s();this.pending=null,r(n),this.router.app&&this.router.app.$nextTick(()=>{t.forEach(t=>{t()})})})})}updateRoute(t){const e=this.current;this.current=t,this.cb&&this.cb(t),this.router.afterHooks.forEach(n=>{n&&n(t,e)})}}function kt(t,e,n,r){const o=mt(t,(t,r,o,i)=>{const s=function(t,e){"function"!=typeof t&&(t=N.extend(t));return t.options[e]}(t,e);if(s)return Array.isArray(s)?s.map(t=>n(t,r,o,i)):n(s,r,o,i)});return gt(r?o.reverse():o)}function Rt(t,e){if(e)return function(){return t.apply(e,arguments)}}class Et extends xt{constructor(t,e){super(t,e);const n=t.options.scrollBehavior,r=pt&&n;r&&rt();const o=At(this.base);window.addEventListener("popstate",e=>{const n=this.current,i=At(this.base);this.current===d&&i===o||this.transitionTo(i,e=>{r&&ot(t,e,n,!0)})})}go(t){window.history.go(t)}push(t,e,n){const{current:r}=this;this.transitionTo(t,t=>{lt(v(this.base+t.fullPath)),ot(this.router,t,r,!1),e&&e(t)},n)}replace(t,e,n){const{current:r}=this;this.transitionTo(t,t=>{ft(v(this.base+t.fullPath)),ot(this.router,t,r,!1),e&&e(t)},n)}ensureURL(t){if(At(this.base)!==this.current.fullPath){const e=v(this.base+this.current.fullPath);t?lt(e):ft(e)}}getCurrentLocation(){return At(this.base)}}function At(t){let e=decodeURI(window.location.pathname);return t&&0===e.indexOf(t)&&(e=e.slice(t.length)),(e||"/")+window.location.search+window.location.hash}class $t extends xt{constructor(t,e,n){super(t,e),n&&function(t){const e=At(t);if(!/^\/#/.test(e))return window.location.replace(v(t+"/#"+e)),!0}(this.base)||Ot()}setupListeners(){const t=this.router.options.scrollBehavior,e=pt&&t;e&&rt(),window.addEventListener(pt?"popstate":"hashchange",()=>{const t=this.current;Ot()&&this.transitionTo(Ct(),n=>{e&&ot(this.router,n,t,!0),pt||Tt(n.fullPath)})})}push(t,e,n){const{current:r}=this;this.transitionTo(t,t=>{St(t.fullPath),ot(this.router,t,r,!1),e&&e(t)},n)}replace(t,e,n){const{current:r}=this;this.transitionTo(t,t=>{Tt(t.fullPath),ot(this.router,t,r,!1),e&&e(t)},n)}go(t){window.history.go(t)}ensureURL(t){const e=this.current.fullPath;Ct()!==e&&(t?St(e):Tt(e))}getCurrentLocation(){return Ct()}}function Ot(){const t=Ct();return"/"===t.charAt(0)||(Tt("/"+t),!1)}function Ct(){let t=window.location.href;const e=t.indexOf("#");if(e<0)return"";const n=(t=t.slice(e+1)).indexOf("?");if(n<0){const e=t.indexOf("#");t=e>-1?decodeURI(t.slice(0,e))+t.slice(e):decodeURI(t)}else n>-1&&(t=decodeURI(t.slice(0,n))+t.slice(n));return t}function jt(t){const e=window.location.href,n=e.indexOf("#");return`${n>=0?e.slice(0,n):e}#${t}`}function St(t){pt?lt(jt(t)):window.location.hash=t}function Tt(t){pt?ft(jt(t)):window.location.replace(jt(t))}class _t extends xt{constructor(t,e){super(t,e),this.stack=[],this.index=-1}push(t,e,n){this.transitionTo(t,t=>{this.stack=this.stack.slice(0,this.index+1).concat(t),this.index++,e&&e(t)},n)}replace(t,e,n){this.transitionTo(t,t=>{this.stack=this.stack.slice(0,this.index).concat(t),e&&e(t)},n)}go(t){const n=this.index+t;if(n<0||n>=this.stack.length)return;const r=this.stack[n];this.confirmTransition(r,()=>{this.index=n,this.updateRoute(r)},t=>{e(vt,t)&&(this.index=n)})}getCurrentLocation(){const t=this.stack[this.stack.length-1];return t?t.fullPath:"/"}ensureURL(){}}class Pt{constructor(t={}){this.app=null,this.apps=[],this.options=t,this.beforeHooks=[],this.resolveHooks=[],this.afterHooks=[],this.matcher=X(t.routes||[],this);let e=t.mode||"hash";switch(this.fallback="history"===e&&!pt&&!1!==t.fallback,this.fallback&&(e="hash"),K||(e="abstract"),this.mode=e,e){case"history":this.history=new Et(this,t.base);break;case"hash":this.history=new $t(this,t.base,this.fallback);break;case"abstract":this.history=new _t(this,t.base)}}match(t,e,n){return this.matcher.match(t,e,n)}get currentRoute(){return this.history&&this.history.current}init(t){if(this.apps.push(t),t.$once("hook:destroyed",()=>{const e=this.apps.indexOf(t);e>-1&&this.apps.splice(e,1),this.app===t&&(this.app=this.apps[0]||null)}),this.app)return;this.app=t;const e=this.history;if(e instanceof Et)e.transitionTo(e.getCurrentLocation());else if(e instanceof $t){const t=()=>{e.setupListeners()};e.transitionTo(e.getCurrentLocation(),t,t)}e.listen(t=>{this.apps.forEach(e=>{e._route=t})})}beforeEach(t){return Lt(this.beforeHooks,t)}beforeResolve(t){return Lt(this.resolveHooks,t)}afterEach(t){return Lt(this.afterHooks,t)}onReady(t,e){this.history.onReady(t,e)}onError(t){this.history.onError(t)}push(t,e,n){if(!e&&!n&&"undefined"!=typeof Promise)return new Promise((e,n)=>{this.history.push(t,e,n)});this.history.push(t,e,n)}replace(t,e,n){if(!e&&!n&&"undefined"!=typeof Promise)return new Promise((e,n)=>{this.history.replace(t,e,n)});this.history.replace(t,e,n)}go(t){this.history.go(t)}back(){this.go(-1)}forward(){this.go(1)}getMatchedComponents(t){const e=t?t.matched?t:this.resolve(t).route:this.currentRoute;return e?[].concat.apply([],e.matched.map(t=>Object.keys(t.components).map(e=>t.components[e]))):[]}resolve(t,e,n){const r=B(t,e=e||this.history.current,n,this),o=this.match(r,e),i=o.redirectedFrom||o.fullPath;return{location:r,route:o,href:function(t,e,n){var r="hash"===n?"#"+e:e;return t?v(t+"/"+r):r}(this.history.base,i,this.mode),normalizedTo:r,resolved:o}}addRoutes(t){this.matcher.addRoutes(t),this.history.current!==d&&this.history.transitionTo(this.history.getCurrentLocation())}}function Lt(t,e){return t.push(e),()=>{const n=t.indexOf(e);n>-1&&t.splice(n,1)}}Pt.install=function t(e){if(t.installed&&N===e)return;t.installed=!0,N=e;const n=t=>void 0!==t,o=(t,e)=>{let r=t.$options._parentVnode;n(r)&&n(r=r.data)&&n(r=r.registerRouteInstance)&&r(t,e)};e.mixin({beforeCreate(){n(this.$options.router)?(this._routerRoot=this,this._router=this.$options.router,this._router.init(this),e.util.defineReactive(this,"_route",this._router.history.current)):this._routerRoot=this.$parent&&this.$parent._routerRoot||this,o(this,this)},destroyed(){o(this)}}),Object.defineProperty(e.prototype,"$router",{get(){return this._routerRoot._router}}),Object.defineProperty(e.prototype,"$route",{get(){return this._routerRoot._route}}),e.component("RouterView",r),e.component("RouterLink",D);const i=e.config.optionMergeStrategies;i.beforeRouteEnter=i.beforeRouteLeave=i.beforeRouteUpdate=i.created},Pt.version="3.1.3",K&&window.Vue&&window.Vue.use(Pt);export default Pt; \ No newline at end of file +function t(t){return Object.prototype.toString.call(t).indexOf("Error")>-1}function e(t,e){return e instanceof t||e&&(e.name===t.name||e._name===t._name)}function n(t,e){for(const n in e)t[n]=e[n];return t}var r={name:"RouterView",functional:!0,props:{name:{type:String,default:"default"}},render(t,{props:e,children:r,parent:o,data:i}){i.routerView=!0;const s=o.$createElement,a=e.name,c=o.$route,u=o._routerViewCache||(o._routerViewCache={});let h=0,p=!1;for(;o&&o._routerRoot!==o;){const t=o.$vnode&&o.$vnode.data;t&&(t.routerView&&h++,t.keepAlive&&o._inactive&&(p=!0)),o=o.$parent}if(i.routerViewDepth=h,p)return s(u[a],i,r);const l=c.matched[h];if(!l)return u[a]=null,s();const f=u[a]=l.components[a];i.registerRouteInstance=(t,e)=>{const n=l.instances[a];(e&&n!==t||!e&&n===t)&&(l.instances[a]=e)},(i.hook||(i.hook={})).prepatch=(t,e)=>{l.instances[a]=e.componentInstance},i.hook.init=t=>{t.data.keepAlive&&t.componentInstance&&t.componentInstance!==l.instances[a]&&(l.instances[a]=t.componentInstance)};let d=i.props=function(t,e){switch(typeof e){case"undefined":return;case"object":return e;case"function":return e(t);case"boolean":return e?t.params:void 0}}(c,l.props&&l.props[a]);if(d){d=i.props=n({},d);const t=i.attrs=i.attrs||{};for(const e in d)f.props&&e in f.props||(t[e]=d[e],delete d[e])}return s(f,i,r)}};const o=/[!'()*]/g,i=t=>"%"+t.charCodeAt(0).toString(16),s=/%2C/g,a=t=>encodeURIComponent(t).replace(o,i).replace(s,","),c=decodeURIComponent;function u(t){const e={};return(t=t.trim().replace(/^(\?|#|&)/,""))?(t.split("&").forEach(t=>{const n=t.replace(/\+/g," ").split("="),r=c(n.shift()),o=n.length>0?c(n.join("=")):null;void 0===e[r]?e[r]=o:Array.isArray(e[r])?e[r].push(o):e[r]=[e[r],o]}),e):e}function h(t){const e=t?Object.keys(t).map(e=>{const n=t[e];if(void 0===n)return"";if(null===n)return a(e);if(Array.isArray(n)){const t=[];return n.forEach(n=>{void 0!==n&&(null===n?t.push(a(e)):t.push(a(e)+"="+a(n)))}),t.join("&")}return a(e)+"="+a(n)}).filter(t=>t.length>0).join("&"):null;return e?`?${e}`:""}const p=/\/?$/;function l(t,e,n,r){const o=r&&r.options.stringifyQuery;let i=e.query||{};try{i=f(i)}catch(t){}const s={name:e.name||t&&t.name,meta:t&&t.meta||{},path:e.path||"/",hash:e.hash||"",query:i,params:e.params||{},fullPath:m(e,o),matched:t?y(t):[]};return n&&(s.redirectedFrom=m(n,o)),Object.freeze(s)}function f(t){if(Array.isArray(t))return t.map(f);if(t&&"object"==typeof t){const e={};for(const n in t)e[n]=f(t[n]);return e}return t}const d=l(null,{path:"/"});function y(t){const e=[];for(;t;)e.unshift(t),t=t.parent;return e}function m({path:t,query:e={},hash:n=""},r){return(t||"/")+(r||h)(e)+n}function g(t,e){return e===d?t===e:!!e&&(t.path&&e.path?t.path.replace(p,"")===e.path.replace(p,"")&&t.hash===e.hash&&w(t.query,e.query):!(!t.name||!e.name)&&(t.name===e.name&&t.hash===e.hash&&w(t.query,e.query)&&w(t.params,e.params)))}function w(t={},e={}){if(!t||!e)return t===e;const n=Object.keys(t),r=Object.keys(e);return n.length===r.length&&n.every(n=>{const r=t[n],o=e[n];return"object"==typeof r&&"object"==typeof o?w(r,o):String(r)===String(o)})}function b(t,e,n){const r=t.charAt(0);if("/"===r)return t;if("?"===r||"#"===r)return e+t;const o=e.split("/");n&&o[o.length-1]||o.pop();const i=t.replace(/^\//,"").split("/");for(let t=0;t=0&&(e=t.slice(r),t=t.slice(0,r));const o=t.indexOf("?");return o>=0&&(n=t.slice(o+1),t=t.slice(0,o)),{path:t,query:n,hash:e}}(i.path||""),a=e&&e.path||"/",c=s.path?b(s.path,a,r||i.append):a,h=function(t,e={},n){const r=n||u;let o;try{o=r(t||"")}catch(t){o={}}for(const t in e)o[t]=e[t];return o}(s.query,i.query,o&&o.options.parseQuery);let p=i.hash||s.hash;return p&&"#"!==p.charAt(0)&&(p=`#${p}`),{_normalized:!0,path:c,query:h,hash:p}}const V=[String,Object],H=[String,Array],z=()=>{};var D={name:"RouterLink",props:{to:{type:V,required:!0},tag:{type:String,default:"a"},exact:Boolean,append:Boolean,replace:Boolean,activeClass:String,exactActiveClass:String,event:{type:H,default:"click"}},render(t){const e=this.$router,r=this.$route,{location:o,route:i,href:s}=e.resolve(this.to,r,this.append),a={},c=e.options.linkActiveClass,u=e.options.linkExactActiveClass,h=null==c?"router-link-active":c,f=null==u?"router-link-exact-active":u,d=null==this.activeClass?h:this.activeClass,y=null==this.exactActiveClass?f:this.exactActiveClass,m=i.redirectedFrom?l(null,B(i.redirectedFrom),null,e):i;a[y]=g(r,m),a[d]=this.exact?a[y]:function(t,e){return 0===t.path.replace(p,"/").indexOf(e.path.replace(p,"/"))&&(!e.hash||t.hash===e.hash)&&function(t,e){for(const n in e)if(!(n in t))return!1;return!0}(t.query,e.query)}(r,m);const w=t=>{F(t)&&(this.replace?e.replace(o,z):e.push(o,z))},b={click:F};Array.isArray(this.event)?this.event.forEach(t=>{b[t]=w}):b[this.event]=w;const v={class:a},x=!this.$scopedSlots.$hasNormal&&this.$scopedSlots.default&&this.$scopedSlots.default({href:s,route:i,navigate:w,isActive:a[d],isExactActive:a[y]});if(x){if(1===x.length)return x[0];if(x.length>1||!x.length)return 0===x.length?t():t("span",{},x)}if("a"===this.tag)v.on=b,v.attrs={href:s};else{const t=function t(e){if(e){let n;for(let r=0;r{!function t(e,n,r,o,i,s){const{path:a,name:c}=o;const u=o.pathToRegexpOptions||{};const h=function(t,e,n){n||(t=t.replace(/\/$/,""));return"/"===t[0]?t:null==e?t:v(`${e.path}/${t}`)}(a,i,u.strict);"boolean"==typeof o.caseSensitive&&(u.sensitive=o.caseSensitive);const p={path:h,regex:Q(h,u),components:o.components||{default:o.component},instances:{},name:c,parent:i,matchAs:s,redirect:o.redirect,beforeEnter:o.beforeEnter,meta:o.meta||{},props:null==o.props?{}:o.components?o.props:{default:o.props}};o.children&&o.children.forEach(o=>{const i=s?v(`${s}/${o.path}`):void 0;t(e,n,r,o,p,i)});n[p.path]||(e.push(p.path),n[p.path]=p);if(void 0!==o.alias){const s=Array.isArray(o.alias)?o.alias:[o.alias];for(let a=0;a!t.optional).map(t=>t.name);if("object"!=typeof c.params&&(c.params={}),i&&"object"==typeof i.params)for(const t in i.params)!(t in c.params)&&e.indexOf(t)>-1&&(c.params[t]=i.params[t]);return c.path=M(t.path,c.params),a(t,c,s)}if(c.path){c.params={};for(let t=0;t{it(),t.state&&t.state.key&&et(t.state.key)})}function ot(t,e,n,r){if(!t.app)return;const o=t.options.scrollBehavior;o&&t.app.$nextTick(()=>{const i=function(){const t=tt();if(t)return nt[t]}(),s=o.call(t,e,n,r?i:null);s&&("function"==typeof s.then?s.then(t=>{ht(t,i)}).catch(t=>{}):ht(s,i))})}function it(){const t=tt();t&&(nt[t]={x:window.pageXOffset,y:window.pageYOffset})}function st(t){return ct(t.x)||ct(t.y)}function at(t){return{x:ct(t.x)?t.x:window.pageXOffset,y:ct(t.y)?t.y:window.pageYOffset}}function ct(t){return"number"==typeof t}const ut=/^#\d/;function ht(t,e){const n="object"==typeof t;if(n&&"string"==typeof t.selector){const n=ut.test(t.selector)?document.getElementById(t.selector.slice(1)):document.querySelector(t.selector);if(n){let o=t.offset&&"object"==typeof t.offset?t.offset:{};e=function(t,e){const n=document.documentElement.getBoundingClientRect(),r=t.getBoundingClientRect();return{x:r.left-n.left-e.x,y:r.top-n.top-e.y}}(n,o={x:ct((r=o).x)?r.x:0,y:ct(r.y)?r.y:0})}else st(t)&&(e=at(t))}else n&&st(t)&&(e=at(t));var r;e&&window.scrollTo(e.x,e.y)}const pt=K&&function(){const t=window.navigator.userAgent;return(-1===t.indexOf("Android 2.")&&-1===t.indexOf("Android 4.0")||-1===t.indexOf("Mobile Safari")||-1!==t.indexOf("Chrome")||-1!==t.indexOf("Windows Phone"))&&(window.history&&"pushState"in window.history)}();function lt(t,e){it();const r=window.history;try{if(e){const e=n({},r.state);e.key=tt(),r.replaceState(e,"",t)}else r.pushState({key:et(G())},"",t)}catch(n){window.location[e?"replace":"assign"](t)}}function ft(t){lt(t,!0)}function dt(t,e,n){const r=o=>{o>=t.length?n():t[o]?e(t[o],()=>{r(o+1)}):r(o+1)};r(0)}function yt(e){return(n,r,o)=>{let i=!1,s=0,a=null;mt(e,(e,n,r,c)=>{if("function"==typeof e&&void 0===e.cid){i=!0,s++;const n=bt(t=>{(function(t){return t.__esModule||wt&&"Module"===t[Symbol.toStringTag]})(t)&&(t=t.default),e.resolved="function"==typeof t?t:N.extend(t),r.components[c]=t,--s<=0&&o()}),u=bt(e=>{const n=`Failed to resolve async component ${c}: ${e}`;a||(a=t(e)?e:new Error(n),o(a))});let h;try{h=e(n,u)}catch(t){u(t)}if(h)if("function"==typeof h.then)h.then(n,u);else{const t=h.component;t&&"function"==typeof t.then&&t.then(n,u)}}}),i||o()}}function mt(t,e){return gt(t.map(t=>Object.keys(t.components).map(n=>e(t.components[n],t.instances[n],t,n))))}function gt(t){return Array.prototype.concat.apply([],t)}const wt="function"==typeof Symbol&&"symbol"==typeof Symbol.toStringTag;function bt(t){let e=!1;return function(...n){if(!e)return e=!0,t.apply(this,n)}}class vt extends Error{constructor(t){super(),this.name=this._name="NavigationDuplicated",this.message=`Navigating to current location ("${t.fullPath}") is not allowed`,Object.defineProperty(this,"stack",{value:(new Error).stack,writable:!0,configurable:!0})}}vt._name="NavigationDuplicated";class xt{constructor(t,e){this.router=t,this.base=function(t){if(!t)if(K){const e=document.querySelector("base");t=(t=e&&e.getAttribute("href")||"/").replace(/^https?:\/\/[^\/]+/,"")}else t="/";"/"!==t.charAt(0)&&(t="/"+t);return t.replace(/\/$/,"")}(e),this.current=d,this.pending=null,this.ready=!1,this.readyCbs=[],this.readyErrorCbs=[],this.errorCbs=[]}listen(t){this.cb=t}onReady(t,e){this.ready?t():(this.readyCbs.push(t),e&&this.readyErrorCbs.push(e))}onError(t){this.errorCbs.push(t)}transitionTo(t,e,n){const r=this.router.match(t,this.current);this.confirmTransition(r,()=>{this.updateRoute(r),e&&e(r),this.ensureURL(),this.ready||(this.ready=!0,this.readyCbs.forEach(t=>{t(r)}))},t=>{n&&n(t),t&&!this.ready&&(this.ready=!0,this.readyErrorCbs.forEach(e=>{e(t)}))})}confirmTransition(n,r,o){const i=this.current,s=n=>{!e(vt,n)&&t(n)&&(this.errorCbs.length?this.errorCbs.forEach(t=>{t(n)}):console.error(n)),o&&o(n)};if(g(n,i)&&n.matched.length===i.matched.length)return this.ensureURL(),s(new vt(n));const{updated:a,deactivated:c,activated:u}=function(t,e){let n;const r=Math.max(t.length,e.length);for(n=0;nt.beforeEnter),yt(u));this.pending=n;const p=(e,r)=>{if(this.pending!==n)return s();try{e(n,i,e=>{!1===e||t(e)?(this.ensureURL(!0),s(e)):"string"==typeof e||"object"==typeof e&&("string"==typeof e.path||"string"==typeof e.name)?(s(),"object"==typeof e&&e.replace?this.replace(e):this.push(e)):r(e)})}catch(t){s(t)}};dt(h,p,()=>{const t=[];dt(function(t,e,n){return kt(t,"beforeRouteEnter",(t,r,o,i)=>(function(t,e,n,r,o){return function(i,s,a){return t(i,s,t=>{"function"==typeof t&&r.push(()=>{!function t(e,n,r,o){n[r]&&!n[r]._isBeingDestroyed?e(n[r]):o()&&setTimeout(()=>{t(e,n,r,o)},16)}(t,e.instances,n,o)}),a(t)})}})(t,o,i,e,n))}(u,t,()=>this.current===n).concat(this.router.resolveHooks),p,()=>{if(this.pending!==n)return s();this.pending=null,r(n),this.router.app&&this.router.app.$nextTick(()=>{t.forEach(t=>{t()})})})})}updateRoute(t){const e=this.current;this.current=t,this.cb&&this.cb(t),this.router.afterHooks.forEach(n=>{n&&n(t,e)})}}function kt(t,e,n,r){const o=mt(t,(t,r,o,i)=>{const s=function(t,e){"function"!=typeof t&&(t=N.extend(t));return t.options[e]}(t,e);if(s)return Array.isArray(s)?s.map(t=>n(t,r,o,i)):n(s,r,o,i)});return gt(r?o.reverse():o)}function Rt(t,e){if(e)return function(){return t.apply(e,arguments)}}class Et extends xt{constructor(t,e){super(t,e);const n=t.options.scrollBehavior,r=pt&&n;r&&rt();const o=At(this.base);window.addEventListener("popstate",e=>{const n=this.current,i=At(this.base);this.current===d&&i===o||this.transitionTo(i,e=>{r&&ot(t,e,n,!0)})})}go(t){window.history.go(t)}push(t,e,n){const{current:r}=this;this.transitionTo(t,t=>{lt(v(this.base+t.fullPath)),ot(this.router,t,r,!1),e&&e(t)},n)}replace(t,e,n){const{current:r}=this;this.transitionTo(t,t=>{ft(v(this.base+t.fullPath)),ot(this.router,t,r,!1),e&&e(t)},n)}ensureURL(t){if(At(this.base)!==this.current.fullPath){const e=v(this.base+this.current.fullPath);t?lt(e):ft(e)}}getCurrentLocation(){return At(this.base)}}function At(t){let e=decodeURI(window.location.pathname);return t&&0===e.indexOf(t)&&(e=e.slice(t.length)),(e||"/")+window.location.search+window.location.hash}class $t extends xt{constructor(t,e,n){super(t,e),n&&function(t){const e=At(t);if(!/^\/#/.test(e))return window.location.replace(v(t+"/#"+e)),!0}(this.base)||Ot()}setupListeners(){const t=this.router.options.scrollBehavior,e=pt&&t;e&&rt(),window.addEventListener(pt?"popstate":"hashchange",()=>{const t=this.current;Ot()&&this.transitionTo(Ct(),n=>{e&&ot(this.router,n,t,!0),pt||Tt(n.fullPath)})})}push(t,e,n){const{current:r}=this;this.transitionTo(t,t=>{St(t.fullPath),ot(this.router,t,r,!1),e&&e(t)},n)}replace(t,e,n){const{current:r}=this;this.transitionTo(t,t=>{Tt(t.fullPath),ot(this.router,t,r,!1),e&&e(t)},n)}go(t){window.history.go(t)}ensureURL(t){const e=this.current.fullPath;Ct()!==e&&(t?St(e):Tt(e))}getCurrentLocation(){return Ct()}}function Ot(){const t=Ct();return"/"===t.charAt(0)||(Tt("/"+t),!1)}function Ct(){let t=window.location.href;const e=t.indexOf("#");if(e<0)return"";const n=(t=t.slice(e+1)).indexOf("?");if(n<0){const e=t.indexOf("#");t=e>-1?decodeURI(t.slice(0,e))+t.slice(e):decodeURI(t)}else t=decodeURI(t.slice(0,n))+t.slice(n);return t}function jt(t){const e=window.location.href,n=e.indexOf("#");return`${n>=0?e.slice(0,n):e}#${t}`}function St(t){pt?lt(jt(t)):window.location.hash=t}function Tt(t){pt?ft(jt(t)):window.location.replace(jt(t))}class _t extends xt{constructor(t,e){super(t,e),this.stack=[],this.index=-1}push(t,e,n){this.transitionTo(t,t=>{this.stack=this.stack.slice(0,this.index+1).concat(t),this.index++,e&&e(t)},n)}replace(t,e,n){this.transitionTo(t,t=>{this.stack=this.stack.slice(0,this.index).concat(t),e&&e(t)},n)}go(t){const n=this.index+t;if(n<0||n>=this.stack.length)return;const r=this.stack[n];this.confirmTransition(r,()=>{this.index=n,this.updateRoute(r)},t=>{e(vt,t)&&(this.index=n)})}getCurrentLocation(){const t=this.stack[this.stack.length-1];return t?t.fullPath:"/"}ensureURL(){}}class Pt{constructor(t={}){this.app=null,this.apps=[],this.options=t,this.beforeHooks=[],this.resolveHooks=[],this.afterHooks=[],this.matcher=X(t.routes||[],this);let e=t.mode||"hash";switch(this.fallback="history"===e&&!pt&&!1!==t.fallback,this.fallback&&(e="hash"),K||(e="abstract"),this.mode=e,e){case"history":this.history=new Et(this,t.base);break;case"hash":this.history=new $t(this,t.base,this.fallback);break;case"abstract":this.history=new _t(this,t.base)}}match(t,e,n){return this.matcher.match(t,e,n)}get currentRoute(){return this.history&&this.history.current}init(t){if(this.apps.push(t),t.$once("hook:destroyed",()=>{const e=this.apps.indexOf(t);e>-1&&this.apps.splice(e,1),this.app===t&&(this.app=this.apps[0]||null)}),this.app)return;this.app=t;const e=this.history;if(e instanceof Et)e.transitionTo(e.getCurrentLocation());else if(e instanceof $t){const t=()=>{e.setupListeners()};e.transitionTo(e.getCurrentLocation(),t,t)}e.listen(t=>{this.apps.forEach(e=>{e._route=t})})}beforeEach(t){return Lt(this.beforeHooks,t)}beforeResolve(t){return Lt(this.resolveHooks,t)}afterEach(t){return Lt(this.afterHooks,t)}onReady(t,e){this.history.onReady(t,e)}onError(t){this.history.onError(t)}push(t,e,n){if(!e&&!n&&"undefined"!=typeof Promise)return new Promise((e,n)=>{this.history.push(t,e,n)});this.history.push(t,e,n)}replace(t,e,n){if(!e&&!n&&"undefined"!=typeof Promise)return new Promise((e,n)=>{this.history.replace(t,e,n)});this.history.replace(t,e,n)}go(t){this.history.go(t)}back(){this.go(-1)}forward(){this.go(1)}getMatchedComponents(t){const e=t?t.matched?t:this.resolve(t).route:this.currentRoute;return e?[].concat.apply([],e.matched.map(t=>Object.keys(t.components).map(e=>t.components[e]))):[]}resolve(t,e,n){const r=B(t,e=e||this.history.current,n,this),o=this.match(r,e),i=o.redirectedFrom||o.fullPath;return{location:r,route:o,href:function(t,e,n){var r="hash"===n?"#"+e:e;return t?v(t+"/"+r):r}(this.history.base,i,this.mode),normalizedTo:r,resolved:o}}addRoutes(t){this.matcher.addRoutes(t),this.history.current!==d&&this.history.transitionTo(this.history.getCurrentLocation())}}function Lt(t,e){return t.push(e),()=>{const n=t.indexOf(e);n>-1&&t.splice(n,1)}}Pt.install=function t(e){if(t.installed&&N===e)return;t.installed=!0,N=e;const n=t=>void 0!==t,o=(t,e)=>{let r=t.$options._parentVnode;n(r)&&n(r=r.data)&&n(r=r.registerRouteInstance)&&r(t,e)};e.mixin({beforeCreate(){n(this.$options.router)?(this._routerRoot=this,this._router=this.$options.router,this._router.init(this),e.util.defineReactive(this,"_route",this._router.history.current)):this._routerRoot=this.$parent&&this.$parent._routerRoot||this,o(this,this)},destroyed(){o(this)}}),Object.defineProperty(e.prototype,"$router",{get(){return this._routerRoot._router}}),Object.defineProperty(e.prototype,"$route",{get(){return this._routerRoot._route}}),e.component("RouterView",r),e.component("RouterLink",D);const i=e.config.optionMergeStrategies;i.beforeRouteEnter=i.beforeRouteLeave=i.beforeRouteUpdate=i.created},Pt.version="3.1.4",K&&window.Vue&&window.Vue.use(Pt);export default Pt; \ No newline at end of file diff --git a/dist/vue-router.esm.js b/dist/vue-router.esm.js index 39056e64b..cc4b7ef45 100644 --- a/dist/vue-router.esm.js +++ b/dist/vue-router.esm.js @@ -1,6 +1,6 @@ /*! - * vue-router v3.1.3 - * (c) 2019 Evan You + * vue-router v3.1.4 + * (c) 2020 Evan You * @license MIT */ /* */ @@ -922,7 +922,8 @@ function fillParams ( return filler(params, { pretty: true }) } catch (e) { if (process.env.NODE_ENV !== 'production') { - warn(false, ("missing param for " + routeMsg + ": " + (e.message))); + // Fix #3072 no warn if `pathMatch` is string + warn(typeof params.pathMatch === 'string', ("missing param for " + routeMsg + ": " + (e.message))); } return '' } finally { @@ -944,20 +945,25 @@ function normalizeLocation ( if (next._normalized) { return next } else if (next.name) { - return extend({}, raw) + next = extend({}, raw); + var params = next.params; + if (params && typeof params === 'object') { + next.params = extend({}, params); + } + return next } // relative params if (!next.path && next.params && current) { next = extend({}, next); next._normalized = true; - var params = extend(extend({}, current.params), next.params); + var params$1 = extend(extend({}, current.params), next.params); if (current.name) { next.name = current.name; - next.params = params; + next.params = params$1; } else if (current.matched.length) { var rawPath = current.matched[current.matched.length - 1].path; - next.path = fillParams(rawPath, params, ("path " + (current.path))); + next.path = fillParams(rawPath, params$1, ("path " + (current.path))); } else if (process.env.NODE_ENV !== 'production') { warn(false, "relative params navigation requires a current route."); } @@ -1097,7 +1103,7 @@ var Link = { if (process.env.NODE_ENV !== 'production') { warn( false, - ("RouterLink with to=\"" + (this.props.to) + "\" is trying to use a scoped slot but it didn't provide exactly one child.") + ("RouterLink with to=\"" + (this.to) + "\" is trying to use a scoped slot but it didn't provide exactly one child. Wrapping the content with a span element.") ); } return scopedSlot.length === 0 ? h() : h('span', {}, scopedSlot) @@ -1822,7 +1828,10 @@ function pushState (url, replace) { var history = window.history; try { if (replace) { - history.replaceState({ key: getStateKey() }, '', url); + // preserve existing history state as it could be overriden by the user + var stateCopy = extend({}, history.state); + stateCopy.key = getStateKey(); + history.replaceState(stateCopy, '', url); } else { history.pushState({ key: setStateKey(genStateKey()) }, '', url); } @@ -2537,9 +2546,7 @@ function getHash () { href = decodeURI(href.slice(0, hashIndex)) + href.slice(hashIndex); } else { href = decodeURI(href); } } else { - if (searchIndex > -1) { - href = decodeURI(href.slice(0, searchIndex)) + href.slice(searchIndex); - } + href = decodeURI(href.slice(0, searchIndex)) + href.slice(searchIndex); } return href @@ -2873,7 +2880,7 @@ function createHref (base, fullPath, mode) { } VueRouter.install = install; -VueRouter.version = '3.1.3'; +VueRouter.version = '3.1.4'; if (inBrowser && window.Vue) { window.Vue.use(VueRouter); diff --git a/dist/vue-router.js b/dist/vue-router.js index fa6ff7c86..3a3482104 100644 --- a/dist/vue-router.js +++ b/dist/vue-router.js @@ -1,6 +1,6 @@ /*! - * vue-router v3.1.3 - * (c) 2019 Evan You + * vue-router v3.1.4 + * (c) 2020 Evan You * @license MIT */ (function (global, factory) { @@ -928,7 +928,8 @@ return filler(params, { pretty: true }) } catch (e) { { - warn(false, ("missing param for " + routeMsg + ": " + (e.message))); + // Fix #3072 no warn if `pathMatch` is string + warn(typeof params.pathMatch === 'string', ("missing param for " + routeMsg + ": " + (e.message))); } return '' } finally { @@ -950,20 +951,25 @@ if (next._normalized) { return next } else if (next.name) { - return extend({}, raw) + next = extend({}, raw); + var params = next.params; + if (params && typeof params === 'object') { + next.params = extend({}, params); + } + return next } // relative params if (!next.path && next.params && current) { next = extend({}, next); next._normalized = true; - var params = extend(extend({}, current.params), next.params); + var params$1 = extend(extend({}, current.params), next.params); if (current.name) { next.name = current.name; - next.params = params; + next.params = params$1; } else if (current.matched.length) { var rawPath = current.matched[current.matched.length - 1].path; - next.path = fillParams(rawPath, params, ("path " + (current.path))); + next.path = fillParams(rawPath, params$1, ("path " + (current.path))); } else { warn(false, "relative params navigation requires a current route."); } @@ -1103,7 +1109,7 @@ { warn( false, - ("RouterLink with to=\"" + (this.props.to) + "\" is trying to use a scoped slot but it didn't provide exactly one child.") + ("RouterLink with to=\"" + (this.to) + "\" is trying to use a scoped slot but it didn't provide exactly one child. Wrapping the content with a span element.") ); } return scopedSlot.length === 0 ? h() : h('span', {}, scopedSlot) @@ -1828,7 +1834,10 @@ var history = window.history; try { if (replace) { - history.replaceState({ key: getStateKey() }, '', url); + // preserve existing history state as it could be overriden by the user + var stateCopy = extend({}, history.state); + stateCopy.key = getStateKey(); + history.replaceState(stateCopy, '', url); } else { history.pushState({ key: setStateKey(genStateKey()) }, '', url); } @@ -2543,9 +2552,7 @@ href = decodeURI(href.slice(0, hashIndex)) + href.slice(hashIndex); } else { href = decodeURI(href); } } else { - if (searchIndex > -1) { - href = decodeURI(href.slice(0, searchIndex)) + href.slice(searchIndex); - } + href = decodeURI(href.slice(0, searchIndex)) + href.slice(searchIndex); } return href @@ -2879,7 +2886,7 @@ } VueRouter.install = install; - VueRouter.version = '3.1.3'; + VueRouter.version = '3.1.4'; if (inBrowser && window.Vue) { window.Vue.use(VueRouter); diff --git a/dist/vue-router.min.js b/dist/vue-router.min.js index b94a0856c..b483630d0 100644 --- a/dist/vue-router.min.js +++ b/dist/vue-router.min.js @@ -1,6 +1,6 @@ /*! - * vue-router v3.1.3 - * (c) 2019 Evan You + * vue-router v3.1.4 + * (c) 2020 Evan You * @license MIT */ -var t,e;t=this,e=function(){"use strict";function t(t){return Object.prototype.toString.call(t).indexOf("Error")>-1}function e(t,e){return e instanceof t||e&&(e.name===t.name||e._name===t._name)}function r(t,e){for(var r in e)t[r]=e[r];return t}var n={name:"RouterView",functional:!0,props:{name:{type:String,default:"default"}},render:function(t,e){var n=e.props,o=e.children,i=e.parent,a=e.data;a.routerView=!0;for(var c=i.$createElement,u=n.name,s=i.$route,p=i._routerViewCache||(i._routerViewCache={}),f=0,h=!1;i&&i._routerRoot!==i;){var l=i.$vnode&&i.$vnode.data;l&&(l.routerView&&f++,l.keepAlive&&i._inactive&&(h=!0)),i=i.$parent}if(a.routerViewDepth=f,h)return c(p[u],a,o);var d=s.matched[f];if(!d)return p[u]=null,c();var v=p[u]=d.components[u];a.registerRouteInstance=function(t,e){var r=d.instances[u];(e&&r!==t||!e&&r===t)&&(d.instances[u]=e)},(a.hook||(a.hook={})).prepatch=function(t,e){d.instances[u]=e.componentInstance},a.hook.init=function(t){t.data.keepAlive&&t.componentInstance&&t.componentInstance!==d.instances[u]&&(d.instances[u]=t.componentInstance)};var y=a.props=function(t,e){switch(typeof e){case"undefined":return;case"object":return e;case"function":return e(t);case"boolean":return e?t.params:void 0}}(s,d.props&&d.props[u]);if(y){y=a.props=r({},y);var m=a.attrs=a.attrs||{};for(var g in y)v.props&&g in v.props||(m[g]=y[g],delete y[g])}return c(v,a,o)}},o=/[!'()*]/g,i=function(t){return"%"+t.charCodeAt(0).toString(16)},a=/%2C/g,c=function(t){return encodeURIComponent(t).replace(o,i).replace(a,",")},u=decodeURIComponent;function s(t){var e={};return(t=t.trim().replace(/^(\?|#|&)/,""))?(t.split("&").forEach(function(t){var r=t.replace(/\+/g," ").split("="),n=u(r.shift()),o=r.length>0?u(r.join("=")):null;void 0===e[n]?e[n]=o:Array.isArray(e[n])?e[n].push(o):e[n]=[e[n],o]}),e):e}function p(t){var e=t?Object.keys(t).map(function(e){var r=t[e];if(void 0===r)return"";if(null===r)return c(e);if(Array.isArray(r)){var n=[];return r.forEach(function(t){void 0!==t&&(null===t?n.push(c(e)):n.push(c(e)+"="+c(t)))}),n.join("&")}return c(e)+"="+c(r)}).filter(function(t){return t.length>0}).join("&"):null;return e?"?"+e:""}var f=/\/?$/;function h(t,e,r,n){var o=n&&n.options.stringifyQuery,i=e.query||{};try{i=l(i)}catch(t){}var a={name:e.name||t&&t.name,meta:t&&t.meta||{},path:e.path||"/",hash:e.hash||"",query:i,params:e.params||{},fullPath:y(e,o),matched:t?v(t):[]};return r&&(a.redirectedFrom=y(r,o)),Object.freeze(a)}function l(t){if(Array.isArray(t))return t.map(l);if(t&&"object"==typeof t){var e={};for(var r in t)e[r]=l(t[r]);return e}return t}var d=h(null,{path:"/"});function v(t){for(var e=[];t;)e.unshift(t),t=t.parent;return e}function y(t,e){var r=t.path,n=t.query;void 0===n&&(n={});var o=t.hash;return void 0===o&&(o=""),(r||"/")+(e||p)(n)+o}function m(t,e){return e===d?t===e:!!e&&(t.path&&e.path?t.path.replace(f,"")===e.path.replace(f,"")&&t.hash===e.hash&&g(t.query,e.query):!(!t.name||!e.name)&&t.name===e.name&&t.hash===e.hash&&g(t.query,e.query)&&g(t.params,e.params))}function g(t,e){if(void 0===t&&(t={}),void 0===e&&(e={}),!t||!e)return t===e;var r=Object.keys(t),n=Object.keys(e);return r.length===n.length&&r.every(function(r){var n=t[r],o=e[r];return"object"==typeof n&&"object"==typeof o?g(n,o):String(n)===String(o)})}function b(t,e,r){var n=t.charAt(0);if("/"===n)return t;if("?"===n||"#"===n)return e+t;var o=e.split("/");r&&o[o.length-1]||o.pop();for(var i=t.replace(/^\//,"").split("/"),a=0;a=0&&(e=t.slice(n),t=t.slice(0,n));var o=t.indexOf("?");return o>=0&&(r=t.slice(o+1),t=t.slice(0,o)),{path:t,query:r,hash:e}}(i.path||""),p=e&&e.path||"/",f=u.path?b(u.path,p,n||i.append):p,h=function(t,e,r){void 0===e&&(e={});var n,o=r||s;try{n=o(t||"")}catch(t){n={}}for(var i in e)n[i]=e[i];return n}(u.query,i.query,o&&o.options.parseQuery),l=i.hash||u.hash;return l&&"#"!==l.charAt(0)&&(l="#"+l),{_normalized:!0,path:f,query:h,hash:l}}var B,H=[String,Object],z=[String,Array],D=function(){},F={name:"RouterLink",props:{to:{type:H,required:!0},tag:{type:String,default:"a"},exact:Boolean,append:Boolean,replace:Boolean,activeClass:String,exactActiveClass:String,event:{type:z,default:"click"}},render:function(t){var e=this,n=this.$router,o=this.$route,i=n.resolve(this.to,o,this.append),a=i.location,c=i.route,u=i.href,s={},p=n.options.linkActiveClass,l=n.options.linkExactActiveClass,d=null==p?"router-link-active":p,v=null==l?"router-link-exact-active":l,y=null==this.activeClass?d:this.activeClass,g=null==this.exactActiveClass?v:this.exactActiveClass,b=c.redirectedFrom?h(null,V(c.redirectedFrom),null,n):c;s[g]=m(o,b),s[y]=this.exact?s[g]:function(t,e){return 0===t.path.replace(f,"/").indexOf(e.path.replace(f,"/"))&&(!e.hash||t.hash===e.hash)&&function(t,e){for(var r in e)if(!(r in t))return!1;return!0}(t.query,e.query)}(o,b);var w=function(t){N(t)&&(e.replace?n.replace(a,D):n.push(a,D))},x={click:N};Array.isArray(this.event)?this.event.forEach(function(t){x[t]=w}):x[this.event]=w;var k={class:s},R=!this.$scopedSlots.$hasNormal&&this.$scopedSlots.default&&this.$scopedSlots.default({href:u,route:c,navigate:w,isActive:s[y],isExactActive:s[g]});if(R){if(1===R.length)return R[0];if(R.length>1||!R.length)return 0===R.length?t():t("span",{},R)}if("a"===this.tag)k.on=x,k.attrs={href:u};else{var E=function t(e){if(e)for(var r,n=0;n-1&&(c.params[h]=r.params[h]);return c.path=M(p.path,c.params),u(p,c,a)}if(c.path){c.params={};for(var l=0;l=t.length?r():t[o]?e(t[o],function(){n(o+1)}):n(o+1)};n(0)}function yt(e){return function(r,n,o){var i=!1,a=0,c=null;mt(e,function(e,r,n,u){if("function"==typeof e&&void 0===e.cid){i=!0,a++;var s,p=wt(function(t){var r;((r=t).__esModule||bt&&"Module"===r[Symbol.toStringTag])&&(t=t.default),e.resolved="function"==typeof t?t:B.extend(t),n.components[u]=t,--a<=0&&o()}),f=wt(function(e){var r="Failed to resolve async component "+u+": "+e;c||(c=t(e)?e:new Error(r),o(c))});try{s=e(p,f)}catch(t){f(t)}if(s)if("function"==typeof s.then)s.then(p,f);else{var h=s.component;h&&"function"==typeof h.then&&h.then(p,f)}}}),i||o()}}function mt(t,e){return gt(t.map(function(t){return Object.keys(t.components).map(function(r){return e(t.components[r],t.instances[r],t,r)})}))}function gt(t){return Array.prototype.concat.apply([],t)}var bt="function"==typeof Symbol&&"symbol"==typeof Symbol.toStringTag;function wt(t){var e=!1;return function(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];if(!e)return e=!0,t.apply(this,r)}}var xt=function(t){function e(e){t.call(this),this.name=this._name="NavigationDuplicated",this.message='Navigating to current location ("'+e.fullPath+'") is not allowed',Object.defineProperty(this,"stack",{value:(new t).stack,writable:!0,configurable:!0})}return t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e,e}(Error);xt._name="NavigationDuplicated";var kt=function(t,e){this.router=t,this.base=function(t){if(!t)if(K){var e=document.querySelector("base");t=(t=e&&e.getAttribute("href")||"/").replace(/^https?:\/\/[^\/]+/,"")}else t="/";return"/"!==t.charAt(0)&&(t="/"+t),t.replace(/\/$/,"")}(e),this.current=d,this.pending=null,this.ready=!1,this.readyCbs=[],this.readyErrorCbs=[],this.errorCbs=[]};function Rt(t,e,r,n){var o=mt(t,function(t,n,o,i){var a=function(t,e){return"function"!=typeof t&&(t=B.extend(t)),t.options[e]}(t,e);if(a)return Array.isArray(a)?a.map(function(t){return r(t,n,o,i)}):r(a,n,o,i)});return gt(n?o.reverse():o)}function Et(t,e){if(e)return function(){return t.apply(e,arguments)}}kt.prototype.listen=function(t){this.cb=t},kt.prototype.onReady=function(t,e){this.ready?t():(this.readyCbs.push(t),e&&this.readyErrorCbs.push(e))},kt.prototype.onError=function(t){this.errorCbs.push(t)},kt.prototype.transitionTo=function(t,e,r){var n=this,o=this.router.match(t,this.current);this.confirmTransition(o,function(){n.updateRoute(o),e&&e(o),n.ensureURL(),n.ready||(n.ready=!0,n.readyCbs.forEach(function(t){t(o)}))},function(t){r&&r(t),t&&!n.ready&&(n.ready=!0,n.readyErrorCbs.forEach(function(e){e(t)}))})},kt.prototype.confirmTransition=function(r,n,o){var i=this,a=this.current,c=function(r){!e(xt,r)&&t(r)&&(i.errorCbs.length?i.errorCbs.forEach(function(t){t(r)}):console.error(r)),o&&o(r)};if(m(r,a)&&r.matched.length===a.matched.length)return this.ensureURL(),c(new xt(r));var u=function(t,e){var r,n=Math.max(t.length,e.length);for(r=0;r-1?decodeURI(t.slice(0,n))+t.slice(n):decodeURI(t)}else r>-1&&(t=decodeURI(t.slice(0,r))+t.slice(r));return t}function St(t){var e=window.location.href,r=e.indexOf("#");return(r>=0?e.slice(0,r):e)+"#"+t}function $t(t){ht?lt(St(t)):window.location.hash=t}function Tt(t){ht?dt(St(t)):window.location.replace(St(t))}var Pt=function(t){function r(e,r){t.call(this,e,r),this.stack=[],this.index=-1}return t&&(r.__proto__=t),r.prototype=Object.create(t&&t.prototype),r.prototype.constructor=r,r.prototype.push=function(t,e,r){var n=this;this.transitionTo(t,function(t){n.stack=n.stack.slice(0,n.index+1).concat(t),n.index++,e&&e(t)},r)},r.prototype.replace=function(t,e,r){var n=this;this.transitionTo(t,function(t){n.stack=n.stack.slice(0,n.index).concat(t),e&&e(t)},r)},r.prototype.go=function(t){var r=this,n=this.index+t;if(!(n<0||n>=this.stack.length)){var o=this.stack[n];this.confirmTransition(o,function(){r.index=n,r.updateRoute(o)},function(t){e(xt,t)&&(r.index=n)})}},r.prototype.getCurrentLocation=function(){var t=this.stack[this.stack.length-1];return t?t.fullPath:"/"},r.prototype.ensureURL=function(){},r}(kt),Lt=function(t){void 0===t&&(t={}),this.app=null,this.apps=[],this.options=t,this.beforeHooks=[],this.resolveHooks=[],this.afterHooks=[],this.matcher=X(t.routes||[],this);var e=t.mode||"hash";switch(this.fallback="history"===e&&!ht&&!1!==t.fallback,this.fallback&&(e="hash"),K||(e="abstract"),this.mode=e,e){case"history":this.history=new Ot(this,t.base);break;case"hash":this.history=new At(this,t.base,this.fallback);break;case"abstract":this.history=new Pt(this,t.base)}},qt={currentRoute:{configurable:!0}};function Ut(t,e){return t.push(e),function(){var r=t.indexOf(e);r>-1&&t.splice(r,1)}}return Lt.prototype.match=function(t,e,r){return this.matcher.match(t,e,r)},qt.currentRoute.get=function(){return this.history&&this.history.current},Lt.prototype.init=function(t){var e=this;if(this.apps.push(t),t.$once("hook:destroyed",function(){var r=e.apps.indexOf(t);r>-1&&e.apps.splice(r,1),e.app===t&&(e.app=e.apps[0]||null)}),!this.app){this.app=t;var r=this.history;if(r instanceof Ot)r.transitionTo(r.getCurrentLocation());else if(r instanceof At){var n=function(){r.setupListeners()};r.transitionTo(r.getCurrentLocation(),n,n)}r.listen(function(t){e.apps.forEach(function(e){e._route=t})})}},Lt.prototype.beforeEach=function(t){return Ut(this.beforeHooks,t)},Lt.prototype.beforeResolve=function(t){return Ut(this.resolveHooks,t)},Lt.prototype.afterEach=function(t){return Ut(this.afterHooks,t)},Lt.prototype.onReady=function(t,e){this.history.onReady(t,e)},Lt.prototype.onError=function(t){this.history.onError(t)},Lt.prototype.push=function(t,e,r){var n=this;if(!e&&!r&&"undefined"!=typeof Promise)return new Promise(function(e,r){n.history.push(t,e,r)});this.history.push(t,e,r)},Lt.prototype.replace=function(t,e,r){var n=this;if(!e&&!r&&"undefined"!=typeof Promise)return new Promise(function(e,r){n.history.replace(t,e,r)});this.history.replace(t,e,r)},Lt.prototype.go=function(t){this.history.go(t)},Lt.prototype.back=function(){this.go(-1)},Lt.prototype.forward=function(){this.go(1)},Lt.prototype.getMatchedComponents=function(t){var e=t?t.matched?t:this.resolve(t).route:this.currentRoute;return e?[].concat.apply([],e.matched.map(function(t){return Object.keys(t.components).map(function(e){return t.components[e]})})):[]},Lt.prototype.resolve=function(t,e,r){var n=V(t,e=e||this.history.current,r,this),o=this.match(n,e),i=o.redirectedFrom||o.fullPath;return{location:n,route:o,href:function(t,e,r){var n="hash"===r?"#"+e:e;return t?w(t+"/"+n):n}(this.history.base,i,this.mode),normalizedTo:n,resolved:o}},Lt.prototype.addRoutes=function(t){this.matcher.addRoutes(t),this.history.current!==d&&this.history.transitionTo(this.history.getCurrentLocation())},Object.defineProperties(Lt.prototype,qt),Lt.install=function t(e){if(!t.installed||B!==e){t.installed=!0,B=e;var r=function(t){return void 0!==t},o=function(t,e){var n=t.$options._parentVnode;r(n)&&r(n=n.data)&&r(n=n.registerRouteInstance)&&n(t,e)};e.mixin({beforeCreate:function(){r(this.$options.router)?(this._routerRoot=this,this._router=this.$options.router,this._router.init(this),e.util.defineReactive(this,"_route",this._router.history.current)):this._routerRoot=this.$parent&&this.$parent._routerRoot||this,o(this,this)},destroyed:function(){o(this)}}),Object.defineProperty(e.prototype,"$router",{get:function(){return this._routerRoot._router}}),Object.defineProperty(e.prototype,"$route",{get:function(){return this._routerRoot._route}}),e.component("RouterView",n),e.component("RouterLink",F);var i=e.config.optionMergeStrategies;i.beforeRouteEnter=i.beforeRouteLeave=i.beforeRouteUpdate=i.created}},Lt.version="3.1.3",K&&window.Vue&&window.Vue.use(Lt),Lt},"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(t=t||self).VueRouter=e(); \ No newline at end of file +var t,e;t=this,e=function(){"use strict";function t(t){return Object.prototype.toString.call(t).indexOf("Error")>-1}function e(t,e){return e instanceof t||e&&(e.name===t.name||e._name===t._name)}function r(t,e){for(var r in e)t[r]=e[r];return t}var n={name:"RouterView",functional:!0,props:{name:{type:String,default:"default"}},render:function(t,e){var n=e.props,o=e.children,i=e.parent,a=e.data;a.routerView=!0;for(var c=i.$createElement,u=n.name,s=i.$route,p=i._routerViewCache||(i._routerViewCache={}),f=0,h=!1;i&&i._routerRoot!==i;){var l=i.$vnode&&i.$vnode.data;l&&(l.routerView&&f++,l.keepAlive&&i._inactive&&(h=!0)),i=i.$parent}if(a.routerViewDepth=f,h)return c(p[u],a,o);var d=s.matched[f];if(!d)return p[u]=null,c();var v=p[u]=d.components[u];a.registerRouteInstance=function(t,e){var r=d.instances[u];(e&&r!==t||!e&&r===t)&&(d.instances[u]=e)},(a.hook||(a.hook={})).prepatch=function(t,e){d.instances[u]=e.componentInstance},a.hook.init=function(t){t.data.keepAlive&&t.componentInstance&&t.componentInstance!==d.instances[u]&&(d.instances[u]=t.componentInstance)};var y=a.props=function(t,e){switch(typeof e){case"undefined":return;case"object":return e;case"function":return e(t);case"boolean":return e?t.params:void 0}}(s,d.props&&d.props[u]);if(y){y=a.props=r({},y);var m=a.attrs=a.attrs||{};for(var g in y)v.props&&g in v.props||(m[g]=y[g],delete y[g])}return c(v,a,o)}},o=/[!'()*]/g,i=function(t){return"%"+t.charCodeAt(0).toString(16)},a=/%2C/g,c=function(t){return encodeURIComponent(t).replace(o,i).replace(a,",")},u=decodeURIComponent;function s(t){var e={};return(t=t.trim().replace(/^(\?|#|&)/,""))?(t.split("&").forEach(function(t){var r=t.replace(/\+/g," ").split("="),n=u(r.shift()),o=r.length>0?u(r.join("=")):null;void 0===e[n]?e[n]=o:Array.isArray(e[n])?e[n].push(o):e[n]=[e[n],o]}),e):e}function p(t){var e=t?Object.keys(t).map(function(e){var r=t[e];if(void 0===r)return"";if(null===r)return c(e);if(Array.isArray(r)){var n=[];return r.forEach(function(t){void 0!==t&&(null===t?n.push(c(e)):n.push(c(e)+"="+c(t)))}),n.join("&")}return c(e)+"="+c(r)}).filter(function(t){return t.length>0}).join("&"):null;return e?"?"+e:""}var f=/\/?$/;function h(t,e,r,n){var o=n&&n.options.stringifyQuery,i=e.query||{};try{i=l(i)}catch(t){}var a={name:e.name||t&&t.name,meta:t&&t.meta||{},path:e.path||"/",hash:e.hash||"",query:i,params:e.params||{},fullPath:y(e,o),matched:t?v(t):[]};return r&&(a.redirectedFrom=y(r,o)),Object.freeze(a)}function l(t){if(Array.isArray(t))return t.map(l);if(t&&"object"==typeof t){var e={};for(var r in t)e[r]=l(t[r]);return e}return t}var d=h(null,{path:"/"});function v(t){for(var e=[];t;)e.unshift(t),t=t.parent;return e}function y(t,e){var r=t.path,n=t.query;void 0===n&&(n={});var o=t.hash;return void 0===o&&(o=""),(r||"/")+(e||p)(n)+o}function m(t,e){return e===d?t===e:!!e&&(t.path&&e.path?t.path.replace(f,"")===e.path.replace(f,"")&&t.hash===e.hash&&g(t.query,e.query):!(!t.name||!e.name)&&t.name===e.name&&t.hash===e.hash&&g(t.query,e.query)&&g(t.params,e.params))}function g(t,e){if(void 0===t&&(t={}),void 0===e&&(e={}),!t||!e)return t===e;var r=Object.keys(t),n=Object.keys(e);return r.length===n.length&&r.every(function(r){var n=t[r],o=e[r];return"object"==typeof n&&"object"==typeof o?g(n,o):String(n)===String(o)})}function b(t,e,r){var n=t.charAt(0);if("/"===n)return t;if("?"===n||"#"===n)return e+t;var o=e.split("/");r&&o[o.length-1]||o.pop();for(var i=t.replace(/^\//,"").split("/"),a=0;a=0&&(e=t.slice(n),t=t.slice(0,n));var o=t.indexOf("?");return o>=0&&(r=t.slice(o+1),t=t.slice(0,o)),{path:t,query:r,hash:e}}(i.path||""),f=e&&e.path||"/",h=p.path?b(p.path,f,n||i.append):f,l=function(t,e,r){void 0===e&&(e={});var n,o=r||s;try{n=o(t||"")}catch(t){n={}}for(var i in e)n[i]=e[i];return n}(p.query,i.query,o&&o.options.parseQuery),d=i.hash||p.hash;return d&&"#"!==d.charAt(0)&&(d="#"+d),{_normalized:!0,path:h,query:l,hash:d}}var B,H=[String,Object],z=[String,Array],D=function(){},F={name:"RouterLink",props:{to:{type:H,required:!0},tag:{type:String,default:"a"},exact:Boolean,append:Boolean,replace:Boolean,activeClass:String,exactActiveClass:String,event:{type:z,default:"click"}},render:function(t){var e=this,n=this.$router,o=this.$route,i=n.resolve(this.to,o,this.append),a=i.location,c=i.route,u=i.href,s={},p=n.options.linkActiveClass,l=n.options.linkExactActiveClass,d=null==p?"router-link-active":p,v=null==l?"router-link-exact-active":l,y=null==this.activeClass?d:this.activeClass,g=null==this.exactActiveClass?v:this.exactActiveClass,b=c.redirectedFrom?h(null,V(c.redirectedFrom),null,n):c;s[g]=m(o,b),s[y]=this.exact?s[g]:function(t,e){return 0===t.path.replace(f,"/").indexOf(e.path.replace(f,"/"))&&(!e.hash||t.hash===e.hash)&&function(t,e){for(var r in e)if(!(r in t))return!1;return!0}(t.query,e.query)}(o,b);var w=function(t){N(t)&&(e.replace?n.replace(a,D):n.push(a,D))},x={click:N};Array.isArray(this.event)?this.event.forEach(function(t){x[t]=w}):x[this.event]=w;var k={class:s},R=!this.$scopedSlots.$hasNormal&&this.$scopedSlots.default&&this.$scopedSlots.default({href:u,route:c,navigate:w,isActive:s[y],isExactActive:s[g]});if(R){if(1===R.length)return R[0];if(R.length>1||!R.length)return 0===R.length?t():t("span",{},R)}if("a"===this.tag)k.on=x,k.attrs={href:u};else{var E=function t(e){if(e)for(var r,n=0;n-1&&(c.params[h]=r.params[h]);return c.path=M(p.path,c.params),u(p,c,a)}if(c.path){c.params={};for(var l=0;l=t.length?r():t[o]?e(t[o],function(){n(o+1)}):n(o+1)};n(0)}function yt(e){return function(r,n,o){var i=!1,a=0,c=null;mt(e,function(e,r,n,u){if("function"==typeof e&&void 0===e.cid){i=!0,a++;var s,p=wt(function(t){var r;((r=t).__esModule||bt&&"Module"===r[Symbol.toStringTag])&&(t=t.default),e.resolved="function"==typeof t?t:B.extend(t),n.components[u]=t,--a<=0&&o()}),f=wt(function(e){var r="Failed to resolve async component "+u+": "+e;c||(c=t(e)?e:new Error(r),o(c))});try{s=e(p,f)}catch(t){f(t)}if(s)if("function"==typeof s.then)s.then(p,f);else{var h=s.component;h&&"function"==typeof h.then&&h.then(p,f)}}}),i||o()}}function mt(t,e){return gt(t.map(function(t){return Object.keys(t.components).map(function(r){return e(t.components[r],t.instances[r],t,r)})}))}function gt(t){return Array.prototype.concat.apply([],t)}var bt="function"==typeof Symbol&&"symbol"==typeof Symbol.toStringTag;function wt(t){var e=!1;return function(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];if(!e)return e=!0,t.apply(this,r)}}var xt=function(t){function e(e){t.call(this),this.name=this._name="NavigationDuplicated",this.message='Navigating to current location ("'+e.fullPath+'") is not allowed',Object.defineProperty(this,"stack",{value:(new t).stack,writable:!0,configurable:!0})}return t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e,e}(Error);xt._name="NavigationDuplicated";var kt=function(t,e){this.router=t,this.base=function(t){if(!t)if(K){var e=document.querySelector("base");t=(t=e&&e.getAttribute("href")||"/").replace(/^https?:\/\/[^\/]+/,"")}else t="/";return"/"!==t.charAt(0)&&(t="/"+t),t.replace(/\/$/,"")}(e),this.current=d,this.pending=null,this.ready=!1,this.readyCbs=[],this.readyErrorCbs=[],this.errorCbs=[]};function Rt(t,e,r,n){var o=mt(t,function(t,n,o,i){var a=function(t,e){return"function"!=typeof t&&(t=B.extend(t)),t.options[e]}(t,e);if(a)return Array.isArray(a)?a.map(function(t){return r(t,n,o,i)}):r(a,n,o,i)});return gt(n?o.reverse():o)}function Et(t,e){if(e)return function(){return t.apply(e,arguments)}}kt.prototype.listen=function(t){this.cb=t},kt.prototype.onReady=function(t,e){this.ready?t():(this.readyCbs.push(t),e&&this.readyErrorCbs.push(e))},kt.prototype.onError=function(t){this.errorCbs.push(t)},kt.prototype.transitionTo=function(t,e,r){var n=this,o=this.router.match(t,this.current);this.confirmTransition(o,function(){n.updateRoute(o),e&&e(o),n.ensureURL(),n.ready||(n.ready=!0,n.readyCbs.forEach(function(t){t(o)}))},function(t){r&&r(t),t&&!n.ready&&(n.ready=!0,n.readyErrorCbs.forEach(function(e){e(t)}))})},kt.prototype.confirmTransition=function(r,n,o){var i=this,a=this.current,c=function(r){!e(xt,r)&&t(r)&&(i.errorCbs.length?i.errorCbs.forEach(function(t){t(r)}):console.error(r)),o&&o(r)};if(m(r,a)&&r.matched.length===a.matched.length)return this.ensureURL(),c(new xt(r));var u=function(t,e){var r,n=Math.max(t.length,e.length);for(r=0;r-1?decodeURI(t.slice(0,n))+t.slice(n):decodeURI(t)}else t=decodeURI(t.slice(0,r))+t.slice(r);return t}function St(t){var e=window.location.href,r=e.indexOf("#");return(r>=0?e.slice(0,r):e)+"#"+t}function $t(t){ht?lt(St(t)):window.location.hash=t}function Tt(t){ht?dt(St(t)):window.location.replace(St(t))}var Pt=function(t){function r(e,r){t.call(this,e,r),this.stack=[],this.index=-1}return t&&(r.__proto__=t),r.prototype=Object.create(t&&t.prototype),r.prototype.constructor=r,r.prototype.push=function(t,e,r){var n=this;this.transitionTo(t,function(t){n.stack=n.stack.slice(0,n.index+1).concat(t),n.index++,e&&e(t)},r)},r.prototype.replace=function(t,e,r){var n=this;this.transitionTo(t,function(t){n.stack=n.stack.slice(0,n.index).concat(t),e&&e(t)},r)},r.prototype.go=function(t){var r=this,n=this.index+t;if(!(n<0||n>=this.stack.length)){var o=this.stack[n];this.confirmTransition(o,function(){r.index=n,r.updateRoute(o)},function(t){e(xt,t)&&(r.index=n)})}},r.prototype.getCurrentLocation=function(){var t=this.stack[this.stack.length-1];return t?t.fullPath:"/"},r.prototype.ensureURL=function(){},r}(kt),Lt=function(t){void 0===t&&(t={}),this.app=null,this.apps=[],this.options=t,this.beforeHooks=[],this.resolveHooks=[],this.afterHooks=[],this.matcher=X(t.routes||[],this);var e=t.mode||"hash";switch(this.fallback="history"===e&&!ht&&!1!==t.fallback,this.fallback&&(e="hash"),K||(e="abstract"),this.mode=e,e){case"history":this.history=new Ot(this,t.base);break;case"hash":this.history=new At(this,t.base,this.fallback);break;case"abstract":this.history=new Pt(this,t.base)}},qt={currentRoute:{configurable:!0}};function Ut(t,e){return t.push(e),function(){var r=t.indexOf(e);r>-1&&t.splice(r,1)}}return Lt.prototype.match=function(t,e,r){return this.matcher.match(t,e,r)},qt.currentRoute.get=function(){return this.history&&this.history.current},Lt.prototype.init=function(t){var e=this;if(this.apps.push(t),t.$once("hook:destroyed",function(){var r=e.apps.indexOf(t);r>-1&&e.apps.splice(r,1),e.app===t&&(e.app=e.apps[0]||null)}),!this.app){this.app=t;var r=this.history;if(r instanceof Ot)r.transitionTo(r.getCurrentLocation());else if(r instanceof At){var n=function(){r.setupListeners()};r.transitionTo(r.getCurrentLocation(),n,n)}r.listen(function(t){e.apps.forEach(function(e){e._route=t})})}},Lt.prototype.beforeEach=function(t){return Ut(this.beforeHooks,t)},Lt.prototype.beforeResolve=function(t){return Ut(this.resolveHooks,t)},Lt.prototype.afterEach=function(t){return Ut(this.afterHooks,t)},Lt.prototype.onReady=function(t,e){this.history.onReady(t,e)},Lt.prototype.onError=function(t){this.history.onError(t)},Lt.prototype.push=function(t,e,r){var n=this;if(!e&&!r&&"undefined"!=typeof Promise)return new Promise(function(e,r){n.history.push(t,e,r)});this.history.push(t,e,r)},Lt.prototype.replace=function(t,e,r){var n=this;if(!e&&!r&&"undefined"!=typeof Promise)return new Promise(function(e,r){n.history.replace(t,e,r)});this.history.replace(t,e,r)},Lt.prototype.go=function(t){this.history.go(t)},Lt.prototype.back=function(){this.go(-1)},Lt.prototype.forward=function(){this.go(1)},Lt.prototype.getMatchedComponents=function(t){var e=t?t.matched?t:this.resolve(t).route:this.currentRoute;return e?[].concat.apply([],e.matched.map(function(t){return Object.keys(t.components).map(function(e){return t.components[e]})})):[]},Lt.prototype.resolve=function(t,e,r){var n=V(t,e=e||this.history.current,r,this),o=this.match(n,e),i=o.redirectedFrom||o.fullPath;return{location:n,route:o,href:function(t,e,r){var n="hash"===r?"#"+e:e;return t?w(t+"/"+n):n}(this.history.base,i,this.mode),normalizedTo:n,resolved:o}},Lt.prototype.addRoutes=function(t){this.matcher.addRoutes(t),this.history.current!==d&&this.history.transitionTo(this.history.getCurrentLocation())},Object.defineProperties(Lt.prototype,qt),Lt.install=function t(e){if(!t.installed||B!==e){t.installed=!0,B=e;var r=function(t){return void 0!==t},o=function(t,e){var n=t.$options._parentVnode;r(n)&&r(n=n.data)&&r(n=n.registerRouteInstance)&&n(t,e)};e.mixin({beforeCreate:function(){r(this.$options.router)?(this._routerRoot=this,this._router=this.$options.router,this._router.init(this),e.util.defineReactive(this,"_route",this._router.history.current)):this._routerRoot=this.$parent&&this.$parent._routerRoot||this,o(this,this)},destroyed:function(){o(this)}}),Object.defineProperty(e.prototype,"$router",{get:function(){return this._routerRoot._router}}),Object.defineProperty(e.prototype,"$route",{get:function(){return this._routerRoot._route}}),e.component("RouterView",n),e.component("RouterLink",F);var i=e.config.optionMergeStrategies;i.beforeRouteEnter=i.beforeRouteLeave=i.beforeRouteUpdate=i.created}},Lt.version="3.1.4",K&&window.Vue&&window.Vue.use(Lt),Lt},"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(t=t||self).VueRouter=e(); \ No newline at end of file diff --git a/docs/.vuepress/components/Bit.vue b/docs/.vuepress/components/Bit.vue deleted file mode 100644 index 43e79ecbc..000000000 --- a/docs/.vuepress/components/Bit.vue +++ /dev/null @@ -1,8 +0,0 @@ - diff --git a/docs/README.md b/docs/README.md index e6bb82409..0fb596fdf 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,7 +1,5 @@ # Introduction - - :::tip VERSION NOTE For TypeScript users, `vue-router@3.0+` requires `vue@2.5+`, and vice versa. ::: diff --git a/docs/api/README.md b/docs/api/README.md index d716bb7b8..71aada72b 100644 --- a/docs/api/README.md +++ b/docs/api/README.md @@ -4,8 +4,6 @@ sidebar: auto # API Reference - - ## `` `` is the component for enabling user navigation in a router-enabled app. The target location is specified with the `to` prop. It renders as an `` tag with correct `href` by default, but can be configured with the `tag` prop. In addition, the link automatically gets an active CSS class when the target route is active. @@ -167,11 +165,11 @@ If you add a `target="_blank"` to your `a` element, you must omit the `@click="n ## `` -The `` component is a functional component that renders the matched component for the given path. Components rendered in `` can also contain its own ``, which will render components for nested paths. +The `` component is a functional component that renders the matched component for the given path. Components rendered in `` can also contain their own ``, which will render components for nested paths. Any non-name props will be passed along to the rendered component, however most of the time the per-route data is contained in the route's params. -Since it's just a component, it works with `` and ``. When using the both together, make sure to use `` inside: +Since it's just a component, it works with `` and ``. When using them both together, make sure to use `` inside: ```html diff --git a/docs/fr/README.md b/docs/fr/README.md index 3172f6a2e..deb4edcf7 100644 --- a/docs/fr/README.md +++ b/docs/fr/README.md @@ -1,7 +1,5 @@ # Introduction - - :::tip VERSION NOTE Pour les utilisateurs de TypeScript, `vue-router@3.0+` requière `vue@2.5+`, et vice versa. ::: diff --git a/docs/fr/api/README.md b/docs/fr/api/README.md index 42af63eed..a259f9aec 100644 --- a/docs/fr/api/README.md +++ b/docs/fr/api/README.md @@ -4,8 +4,6 @@ sidebar: auto # API - - ## `` `` est le composant pour activer la navigation utilisateur dans une application où le routeur est activé. La localisation cible est spécifiée grâce à la prop `to`. Il est rendu en tant que balise `` avec le `href` correct par défaut, mais peut être configuré grâce à la prop `tag`. De plus, le lien se verra attribuer une classe CSS active lorsque la route cible est active. @@ -55,10 +53,14 @@ Dans ce cas, `` sera le lien actuel (et récupèrera le bon `href`), mais la Accueil - Utilisateur + Utilisateur - S'enregistrer + S'enregistrer ``` ### replace @@ -169,7 +171,7 @@ Le composant `` est un composant fonctionnel qui fait le rendu du c // 2.6.0+ caseSensitive?: boolean, // use case sensitive match? (default: false) - pathToRegexpOptions?: Object, // path-to-regexp options for compiling regex + pathToRegexpOptions?: Object // path-to-regexp options for compiling regex } ``` @@ -361,7 +363,7 @@ L'objet `Route` peut être trouvé à plusieurs endroits : const router = new VueRouter({ scrollBehavior(to, from, savedPosition) { // `to` et `from` sont tous les deux des objets Route - }, + } }) ``` @@ -412,10 +414,10 @@ L'objet `Route` peut être trouvé à plusieurs endroits : component: Foo, children: [ // c'est aussi un itinéraire - { path: 'bar', component: Bar }, - ], - }, - ], + { path: 'bar', component: Bar } + ] + } + ] }) ``` diff --git a/docs/fr/guide/README.md b/docs/fr/guide/README.md index 0047b8993..35756ef40 100644 --- a/docs/fr/guide/README.md +++ b/docs/fr/guide/README.md @@ -1,17 +1,15 @@ # Pour commencer - - ::: tip Note Nous utiliserons [ES2015](https://github.com/lukehoban/es6features) dans les exemples de code dans ce guide. - Tous les exemples utiliseront la version complète de Vue pour rendre l'analyse de template possible. Plus de détails [ici](https://fr.vuejs.org/guide/installation.html#Runtime-Compiler-vs-Runtime-seul). +Tous les exemples utiliseront la version complète de Vue pour rendre l'analyse de template possible. Plus de détails [ici](https://fr.vuejs.org/guide/installation.html#Runtime-Compiler-vs-Runtime-seul). ::: Créer une application monopage avec Vue + Vue Router est vraiment simple. Avec Vue.js, nous concevons déjà notre application avec des composants. En ajoutant vue-router dans notre application, tout ce qu'il nous reste à faire est de relier nos composants aux routes, et de laisser vue-router faire le rendu. Voici un exemple de base : ## HTML -``` html +```html @@ -32,7 +30,7 @@ Créer une application monopage avec Vue + Vue Router est vraiment simple. Avec ## JavaScript -``` js +```js // 0. Si vous utilisez un système de module (par ex. via vue-cli), il faut importer Vue et Vue Router et ensuite appeler `Vue.use(VueRouter)`. // 1. Définissez les composants de route. @@ -73,16 +71,14 @@ En injectant le routeur, nous y avons accès à travers `this.$router`. Nous avo // Home.vue export default { computed: { - username () { + username() { // Nous verrons ce que représente `params` dans un instant. return this.$route.params.username } }, methods: { - goBack () { - window.history.length > 1 - ? this.$router.go(-1) - : this.$router.push('/') + goBack() { + window.history.length > 1 ? this.$router.go(-1) : this.$router.push('/') } } } diff --git a/docs/fr/guide/essentials/dynamic-matching.md b/docs/fr/guide/essentials/dynamic-matching.md index bfee2918f..82ec94354 100644 --- a/docs/fr/guide/essentials/dynamic-matching.md +++ b/docs/fr/guide/essentials/dynamic-matching.md @@ -67,7 +67,7 @@ const User = { ## Motifs de concordance avancés -`vue-router` utilise [path-to-regexp](https://github.com/pillarjs/path-to-regexp) comme moteur de concordance de chemin, il supporte donc plusieurs motifs de concordance avancés tels que la présence optionnelle de segments dynamiques, aucun ou plusieurs motifs, plus d'options par motifs, et même des motifs d'expressions régulières personnalisés. Consultez cette [documentation](https://github.com/pillarjs/path-to-regexp#parameters) pour utiliser ces motifs avancés et [cet exemple](https://github.com/vuejs/vue-router/blob/dev/examples/route-matching/app.js) pour les utiliser avec `vue-router`. +`vue-router` utilise [path-to-regexp](https://github.com/pillarjs/path-to-regexp/tree/v1.7.0) comme moteur de concordance de chemin, il supporte donc plusieurs motifs de concordance avancés tels que la présence optionnelle de segments dynamiques, aucun ou plusieurs motifs, plus d'options par motifs, et même des motifs d'expressions régulières personnalisés. Consultez cette [documentation](https://github.com/pillarjs/path-to-regexp/tree/v1.7.0#parameters) pour utiliser ces motifs avancés et [cet exemple](https://github.com/vuejs/vue-router/blob/dev/examples/route-matching/app.js) pour les utiliser avec `vue-router`. ## Priorité de concordance diff --git a/docs/fr/guide/essentials/redirect-and-alias.md b/docs/fr/guide/essentials/redirect-and-alias.md index ea39015a1..eb9ef163a 100644 --- a/docs/fr/guide/essentials/redirect-and-alias.md +++ b/docs/fr/guide/essentials/redirect-and-alias.md @@ -35,7 +35,7 @@ const router = new VueRouter({ }) ``` -Notez que les [intercepteurs de navigation](../advanced/navigation-guards.md) ne sont pas appliqués sur les routes d'où à lieu la redirection mais uniquement sur les routes cibles. Dans l'exemple ci-dessous, ajouter une interception `beforeEnter` ou `beforeLeave` à la route `/a` n'aura aucun effet. +Notez que les [intercepteurs de navigation](../advanced/navigation-guards.md) ne sont pas appliqués sur les routes d'où à lieu la redirection mais uniquement sur les routes cibles. Dans l'exemple ci-dessous, ajouter une interception `beforeEnter` à la route `/a` n'aura aucun effet. Pour d'autres utilisations avancées, jetez un œil à cet [exemple](https://github.com/vuejs/vue-router/blob/dev/examples/redirect/app.js). diff --git a/docs/guide/README.md b/docs/guide/README.md index a6e87ca0a..00c537027 100644 --- a/docs/guide/README.md +++ b/docs/guide/README.md @@ -1,7 +1,5 @@ # Getting Started - - ::: tip Note We will be using [ES2015](https://github.com/lukehoban/es6features) in the code samples in the guide. @@ -12,7 +10,7 @@ Creating a Single-page Application with Vue + Vue Router is dead simple. With Vu ## HTML -``` html +```html @@ -33,7 +31,7 @@ Creating a Single-page Application with Vue + Vue Router is dead simple. With Vu ## JavaScript -``` js +```js // 0. If using a module system (e.g. via vue-cli), import Vue and VueRouter // and then call `Vue.use(VueRouter)`. @@ -75,16 +73,14 @@ By injecting the router, we get access to it as `this.$router` as well as the cu // Home.vue export default { computed: { - username () { + username() { // We will see what `params` is shortly return this.$route.params.username } }, methods: { - goBack () { - window.history.length > 1 - ? this.$router.go(-1) - : this.$router.push('/') + goBack() { + window.history.length > 1 ? this.$router.go(-1) : this.$router.push('/') } } } diff --git a/docs/guide/advanced/navigation-guards.md b/docs/guide/advanced/navigation-guards.md index acb63f572..61d9bf13c 100644 --- a/docs/guide/advanced/navigation-guards.md +++ b/docs/guide/advanced/navigation-guards.md @@ -8,7 +8,7 @@ Remember that **params or query changes won't trigger enter/leave navigation gua You can register global before guards using `router.beforeEach`: -``` js +```js const router = new VueRouter({ ... }) router.beforeEach((to, from, next) => { @@ -34,7 +34,24 @@ Every guard function receives three arguments: - **`next(error)`**: (2.4.0+) if the argument passed to `next` is an instance of `Error`, the navigation will be aborted and the error will be passed to callbacks registered via [`router.onError()`](../../api/#router-onerror). -**Make sure to always call the `next` function, otherwise the hook will never be resolved.** +**Make sure that the `next` function is called exactly once in any given pass through the navigation guard. It can appear more than once, but only if the logical paths have no overlap, otherwise the hook will never be resolved or produce errors.** Here is an example of redirecting to user to `/login` if they are not authenticated: + +```js +// BAD +router.beforeEach((to, from, next) => { + if (!isAuthenticated) next('/login') + // if the user is not authenticated, `next` is called twice + next() +}) +``` + +```js +// GOOD +router.beforeEach((to, from, next) => { + if (!isAuthenticated) next('/login') + else next() +}) +``` ## Global Resolve Guards @@ -44,7 +61,7 @@ You can register a global guard with `router.beforeResolve`. This is similar to You can also register global after hooks, however unlike guards, these hooks do not get a `next` function and cannot affect the navigation: -``` js +```js router.afterEach((to, from) => { // ... }) @@ -54,7 +71,7 @@ router.afterEach((to, from) => { You can define `beforeEnter` guards directly on a route's configuration object: -``` js +```js const router = new VueRouter({ routes: [ { @@ -78,7 +95,7 @@ Finally, you can directly define route navigation guards inside route components - `beforeRouteUpdate` - `beforeRouteLeave` -``` js +```js const Foo = { template: `...`, beforeRouteEnter (to, from, next) { @@ -106,7 +123,7 @@ The `beforeRouteEnter` guard does **NOT** have access to `this`, because the gua However, you can access the instance by passing a callback to `next`. The callback will be called when the navigation is confirmed, and the component instance will be passed to the callback as the argument: -``` js +```js beforeRouteEnter (to, from, next) { next(vm => { // access to component instance via `vm` diff --git a/docs/guide/essentials/dynamic-matching.md b/docs/guide/essentials/dynamic-matching.md index f08c6dc91..12807125b 100644 --- a/docs/guide/essentials/dynamic-matching.md +++ b/docs/guide/essentials/dynamic-matching.md @@ -2,7 +2,7 @@ Very often we will need to map routes with the given pattern to the same component. For example we may have a `User` component which should be rendered for all users but with different user IDs. In `vue-router` we can use a dynamic segment in the path to achieve that: -``` js +```js const User = { template: '
User
' } @@ -19,7 +19,7 @@ Now URLs like `/user/foo` and `/user/bar` will both map to the same route. A dynamic segment is denoted by a colon `:`. When a route is matched, the value of the dynamic segments will be exposed as `this.$route.params` in every component. Therefore, we can render the current user ID by updating `User`'s template to this: -``` js +```js const User = { template: '
User {{ $route.params.id }}
' } @@ -29,9 +29,9 @@ You can check out a live example [here](https://jsfiddle.net/yyx990803/4xfa2f19/ You can have multiple dynamic segments in the same route, and they will map to corresponding fields on `$route.params`. Examples: -| pattern | matched path | $route.params | -|---------|------|--------| -| /user/:username | /user/evan | `{ username: 'evan' }` | +| pattern | matched path | \$route.params | +| ----------------------------- | ------------------- | -------------------------------------- | +| /user/:username | /user/evan | `{ username: 'evan' }` | | /user/:username/post/:post_id | /user/evan/post/123 | `{ username: 'evan', post_id: '123' }` | In addition to `$route.params`, the `$route` object also exposes other useful information such as `$route.query` (if there is a query in the URL), `$route.hash`, etc. You can check out the full details in the [API Reference](../../api/#the-route-object). @@ -42,11 +42,11 @@ One thing to note when using routes with params is that when the user navigates To react to params changes in the same component, you can simply watch the `$route` object: -``` js +```js const User = { template: '...', watch: { - '$route' (to, from) { + $route(to, from) { // react to route changes... } } @@ -55,7 +55,7 @@ const User = { Or, use the `beforeRouteUpdate` [navigation guard](../advanced/navigation-guards.html) introduced in 2.2: -``` js +```js const User = { template: '...', beforeRouteUpdate (to, from, next) { @@ -97,7 +97,7 @@ this.$route.params.pathMatch // '/non-existing' ## Advanced Matching Patterns -`vue-router` uses [path-to-regexp](https://github.com/pillarjs/path-to-regexp) as its path matching engine, so it supports many advanced matching patterns such as optional dynamic segments, zero or more / one or more requirements, and even custom regex patterns. Check out its [documentation](https://github.com/pillarjs/path-to-regexp#parameters) for these advanced patterns, and [this example](https://github.com/vuejs/vue-router/blob/dev/examples/route-matching/app.js) of using them in `vue-router`. +`vue-router` uses [path-to-regexp](https://github.com/pillarjs/path-to-regexp/tree/v1.7.0) as its path matching engine, so it supports many advanced matching patterns such as optional dynamic segments, zero or more / one or more requirements, and even custom regex patterns. Check out its [documentation](https://github.com/pillarjs/path-to-regexp/tree/v1.7.0#parameters) for these advanced patterns, and [this example](https://github.com/vuejs/vue-router/blob/dev/examples/route-matching/app.js) of using them in `vue-router`. ## Matching Priority diff --git a/docs/guide/essentials/history-mode.md b/docs/guide/essentials/history-mode.md index 759c9ea16..5eeaad033 100644 --- a/docs/guide/essentials/history-mode.md +++ b/docs/guide/essentials/history-mode.md @@ -19,6 +19,8 @@ Not to worry: To fix the issue, all you need to do is add a simple catch-all fal ## Example Server Configurations +**Note**: The following examples assume you are serving your app from the root folder. If you deploy to a subfolder, you should use [the `publicPath` option of Vue CLI](https://cli.vuejs.org/config/#publicpath) and the related [`base` property of the router](https://router.vuejs.org/api/#base). You also need to adjust the examples below to use the subfolder instead of the root folder (e.g. replacing `RewriteBase /` with `RewriteBase /name-of-your-subfolder/`). + #### Apache ```apache diff --git a/docs/guide/essentials/named-routes.md b/docs/guide/essentials/named-routes.md index 297457c52..2268f1425 100644 --- a/docs/guide/essentials/named-routes.md +++ b/docs/guide/essentials/named-routes.md @@ -20,7 +20,7 @@ To link to a named route, you can pass an object to the `router-link` component' User ``` -This is the exact same object used programatically with `router.push()`: +This is the exact same object used programmatically with `router.push()`: ``` js router.push({ name: 'user', params: { userId: 123 }}) diff --git a/docs/guide/essentials/redirect-and-alias.md b/docs/guide/essentials/redirect-and-alias.md index 103995bac..887bab2d9 100644 --- a/docs/guide/essentials/redirect-and-alias.md +++ b/docs/guide/essentials/redirect-and-alias.md @@ -35,7 +35,7 @@ const router = new VueRouter({ }) ``` -Note that [Navigation Guards](../advanced/navigation-guards.md) are not applied on the route that redirects, only on its target. In the example below, adding a `beforeEnter` or `beforeLeave` guard to the `/a` route would not have any effect. +Note that [Navigation Guards](../advanced/navigation-guards.md) are not applied on the route that redirects, only on its target. In the example below, adding a `beforeEnter` guard to the `/a` route would not have any effect. For other advanced usage, checkout the [example](https://github.com/vuejs/vue-router/blob/dev/examples/redirect/app.js). diff --git a/docs/ja/guide/advanced/navigation-guards.md b/docs/ja/guide/advanced/navigation-guards.md index 90cb4f54c..13add0f21 100644 --- a/docs/ja/guide/advanced/navigation-guards.md +++ b/docs/ja/guide/advanced/navigation-guards.md @@ -128,7 +128,7 @@ beforeRouteUpdate (to, from, next) { **leave ガード**は、通常、ユーザが保存されていない編集内容で誤って経路を離れるのを防ぐために使用されます。ナビゲーションは `next(false)` を呼び出すことで取り消すことができます。 ```js -beforeRouteLeave (to, from , next) { +beforeRouteLeave (to, from, next) { const answer = window.confirm('Do you really want to leave? you have unsaved changes!') if (answer) { next() diff --git a/docs/ja/guide/essentials/dynamic-matching.md b/docs/ja/guide/essentials/dynamic-matching.md index 2a1658fbe..f1b0d1efa 100644 --- a/docs/ja/guide/essentials/dynamic-matching.md +++ b/docs/ja/guide/essentials/dynamic-matching.md @@ -96,7 +96,7 @@ this.$route.params.pathMatch // '/non-existing' ## 高度なマッチングパターン -`vue-router` はパスのマッチングエンジンとして [path-to-regexp](https://github.com/pillarjs/path-to-regexp) を使っています。これは Optional による動的なセグメント、Zero or more / One or more に対する要求、また、カスタム正規表現パターンまでもサポートしています。 これらの高度なパターンについてはこちらの [ドキュメンテーション](https://github.com/pillarjs/path-to-regexp#parameters) または、 `vue-router` の中でそれらを使っている [こちらの例](https://github.com/vuejs/vue-router/blob/dev/examples/route-matching/app.js) をご参照ください。 +`vue-router` はパスのマッチングエンジンとして [path-to-regexp](https://github.com/pillarjs/path-to-regexp/tree/v1.7.0) を使っています。これは Optional による動的なセグメント、Zero or more / One or more に対する要求、また、カスタム正規表現パターンまでもサポートしています。 これらの高度なパターンについてはこちらの [ドキュメンテーション](https://github.com/pillarjs/path-to-regexp/tree/v1.7.0#parameters) または、 `vue-router` の中でそれらを使っている [こちらの例](https://github.com/vuejs/vue-router/blob/dev/examples/route-matching/app.js) をご参照ください。 ## マッチングの優先度 diff --git a/docs/kr/guide/essentials/dynamic-matching.md b/docs/kr/guide/essentials/dynamic-matching.md index 5c95a5384..85cd66fe8 100644 --- a/docs/kr/guide/essentials/dynamic-matching.md +++ b/docs/kr/guide/essentials/dynamic-matching.md @@ -68,7 +68,7 @@ const User = { ### 고급 매칭 패턴 -`vue-router`는 라우트 매칭 엔진으로 [path-to-regexp](https://github.com/pillarjs/path-to-regexp)를 사용하기 때문에 선택적 동적 세그먼트, 0개 이상/하나 이상의 요구 사항, 심지어 커스텀 정규식 패턴과 같은 많은 고급 매칭 패턴을 지원합니다. 이 고급 패턴들과 `vue-router`에서 사용하는 [예제](https://github.com/vuejs/vue-router/blob/dev/examples/route-matching/app.js)에 대한 [문서](https://github.com/pillarjs/path-to-regexp#parameters)를 확인하십시오. +`vue-router`는 라우트 매칭 엔진으로 [path-to-regexp](https://github.com/pillarjs/path-to-regexp/tree/v1.7.0)를 사용하기 때문에 선택적 동적 세그먼트, 0개 이상/하나 이상의 요구 사항, 심지어 커스텀 정규식 패턴과 같은 많은 고급 매칭 패턴을 지원합니다. 이 고급 패턴들과 `vue-router`에서 사용하는 [예제](https://github.com/vuejs/vue-router/blob/dev/examples/route-matching/app.js)에 대한 [문서](https://github.com/pillarjs/path-to-regexp/tree/v1.7.0#parameters)를 확인하십시오. ### 매칭 우선순위 diff --git a/docs/ru/README.md b/docs/ru/README.md index ca953119d..93ab8691e 100644 --- a/docs/ru/README.md +++ b/docs/ru/README.md @@ -1,7 +1,5 @@ # Введение - - :::tip ПРИМЕЧАНИЕ К ВЕРСИИ Для пользователей TypeScript, `vue-router@3.0+` требуется `vue@2.5+`, и наоборот. ::: diff --git a/docs/ru/api/README.md b/docs/ru/api/README.md index ab2382aa6..aec352514 100644 --- a/docs/ru/api/README.md +++ b/docs/ru/api/README.md @@ -4,8 +4,6 @@ sidebar: auto # Справочник API - - ## `` `` — это компонент предназначенный для навигации пользователя в приложении с клиентской маршрутизацией. Путь назначения указывается входным параметром `to`. По умолчанию компонент рендерится в тег `
` с корректным значением `href`, но это можно изменить входным параметром `tag`. Кроме того, ссылка автоматически получает активный класс CSS при переходе на путь назначения. @@ -167,7 +165,7 @@ sidebar: auto ## `` -Функциональный компонент `` отображает компонент соответствующий данному маршруту. Компоненты внутри `` также могут содержать в шаблоне собственный `` (он будет использован для отображения компонентов вложенных маршрутов). +Функциональный компонент `` отображает компонент соответствующий данному маршруту. Компоненты внутри `` также могут содержать в шаблоне собственный `` (он будет использован для отображения компонентов вложенных маршрутов). Все остальные входные параметры передаются в отображаемый компонент, однако данные маршрута удобнее получать из `$route.params` текущего маршрута. @@ -457,7 +455,7 @@ router.onError(callback) ```js const router = new VueRouter({ - scrollBehavior (to, from, savedPosition) { + scrollBehavior(to, from, savedPosition) { // как `to` так и `from` являются объектами маршрута } }) @@ -475,7 +473,7 @@ router.onError(callback) - тип: `Object` - Объект, который содержит пары ключ/значение динамических сегментов маршрута (включая *-сегменты). Если параметров нет, то значением будет пустой объект. + Объект, который содержит пары ключ/значение динамических сегментов маршрута (включая \*-сегменты). Если параметров нет, то значением будет пустой объект. - **\$route.query** diff --git a/docs/ru/guide/README.md b/docs/ru/guide/README.md index 1c78ee30e..bf767f17a 100644 --- a/docs/ru/guide/README.md +++ b/docs/ru/guide/README.md @@ -1,7 +1,5 @@ # Начало работы - - ::: tip Примечание Мы будем использовать синтаксис [ES2015](https://github.com/lukehoban/es6features) в примерах кода в этом руководстве. @@ -73,16 +71,14 @@ const app = new Vue({ // Home.vue export default { computed: { - username () { + username() { // Мы скоро разберём что такое `params` return this.$route.params.username } }, methods: { - goBack () { - window.history.length > 1 - ? this.$router.go(-1) - : this.$router.push('/') + goBack() { + window.history.length > 1 ? this.$router.go(-1) : this.$router.push('/') } } } diff --git a/docs/ru/guide/advanced/data-fetching.md b/docs/ru/guide/advanced/data-fetching.md index b8786bc44..c0582cd04 100644 --- a/docs/ru/guide/advanced/data-fetching.md +++ b/docs/ru/guide/advanced/data-fetching.md @@ -35,24 +35,24 @@ ```js export default { - data () { + data() { return { loading: false, post: null, error: null } }, - created () { + created() { // загружаем данные, когда представление создано // и данные реактивно отслеживаются this.fetchData() }, watch: { // при изменениях маршрута запрашиваем данные снова - '$route': 'fetchData' + $route: 'fetchData' }, methods: { - fetchData () { + fetchData() { this.error = this.post = null this.loading = true // замените `getPost` используемым методом получения данных / доступа к API diff --git a/docs/ru/guide/advanced/navigation-guards.md b/docs/ru/guide/advanced/navigation-guards.md index f0ccf8adb..e5555d2e3 100644 --- a/docs/ru/guide/advanced/navigation-guards.md +++ b/docs/ru/guide/advanced/navigation-guards.md @@ -34,7 +34,24 @@ router.beforeEach((to, from, next) => { - **`next(error)`**: (добавлено в версии 2.4.0+) если аргумент, переданный `next` является экземпляром `Error`, навигация будет прервана и ошибка будет передана в коллбэк, зарегистрированный через [`router.onError()`](../../api/#router-onerror). -**Убедитесь, что функция `next` будет вызвана, иначе хук никогда не будет разрешён.** +**Убедитесь, что функция `next` будет вызываться в навигационном хуке только 1 раз в любом случае. Вызовы могут встречаться несколько раз, но важно чтобы они не пересекались логически, иначе хук никогда не разрешится или выдаст ошибки.** Вот пример перенаправления пользователя на страницу `/login` если он не авторизован: + +```js +// ПЛОХО +router.beforeEach((to, from, next) => { + if (!isAuthenticated) next('/login') + // если пользователь не авторизован, то `next` будет вызываться дважды + next() +}) +``` + +```js +// ХОРОШО +router.beforeEach((to, from, next) => { + if (!isAuthenticated) next('/login') + else next() +}) +``` ## Глобальные хуки разрешения перехода @@ -139,7 +156,7 @@ beforeRouteLeave (to, from, next) { ## Полная цепочка обработки навигации 1. Срабатывание навигации. -2. Вызов leave-хуков в деактивируемых компонентах. +2. Вызов `beforeRouteLeave` хуков в деактивируемых компонентах. 3. Вызов глобальных `beforeEach` хуков. 4. Вызов `beforeRouteUpdate` хука в переиспользуемых компонентах. 5. Вызов `beforeEnter` в конфигурации маршрута. diff --git a/docs/ru/guide/advanced/transitions.md b/docs/ru/guide/advanced/transitions.md index b88bb068c..1adf3cf2a 100644 --- a/docs/ru/guide/advanced/transitions.md +++ b/docs/ru/guide/advanced/transitions.md @@ -47,7 +47,7 @@ const Bar = { // затем, в родительском компоненте, будем следить за переменной `$route`, // чтобы определить, какой анимационный переход применять watch: { - '$route' (to, from) { + $route(to, from) { const toDepth = to.path.split('/').length const fromDepth = from.path.split('/').length this.transitionName = toDepth < fromDepth ? 'slide-right' : 'slide-left' diff --git a/docs/ru/guide/essentials/dynamic-matching.md b/docs/ru/guide/essentials/dynamic-matching.md index f3e450402..3e86a5925 100644 --- a/docs/ru/guide/essentials/dynamic-matching.md +++ b/docs/ru/guide/essentials/dynamic-matching.md @@ -46,7 +46,7 @@ const User = { const User = { template: '...', watch: { - '$route' (to, from) { + $route(to, from) { // обрабатываем изменение параметров маршрута... } } @@ -97,7 +97,7 @@ this.$route.params.pathMatch // '/non-existing' ## Продвинутые возможности сопоставления -`vue-router` использует [path-to-regexp](https://github.com/pillarjs/path-to-regexp) в качестве движка для проверки совпадения маршрутов, что позволяет задействовать многие продвинутые возможности, включая опциональные динамические сегменты и регулярные выражения. Подробнее об этих продвинутых возможностях можно изучить в [документации библиотеки](https://github.com/pillarjs/path-to-regexp#parameters), а на [примере](https://github.com/vuejs/vue-router/blob/dev/examples/route-matching/app.js) узнать как использовать их совместно с `vue-router`. +`vue-router` использует [path-to-regexp](https://github.com/pillarjs/path-to-regexp/tree/v1.7.0) в качестве движка для проверки совпадения маршрутов, что позволяет задействовать многие продвинутые возможности, включая опциональные динамические сегменты и регулярные выражения. Подробнее об этих продвинутых возможностях можно изучить в [документации библиотеки](https://github.com/pillarjs/path-to-regexp/tree/v1.7.0#parameters), а на [примере](https://github.com/vuejs/vue-router/blob/dev/examples/route-matching/app.js) узнать как использовать их совместно с `vue-router`. ## Приоритеты при сопоставлении маршрутов diff --git a/docs/ru/guide/essentials/history-mode.md b/docs/ru/guide/essentials/history-mode.md index 1128c3b79..0f42bf028 100644 --- a/docs/ru/guide/essentials/history-mode.md +++ b/docs/ru/guide/essentials/history-mode.md @@ -19,6 +19,8 @@ const router = new VueRouter({ ## Примеры конфигурирования серверов +**Примечание**: В примерах ниже предполагается, что приложение публикуется в корневой каталог. При необходимости публикации во вложенный каталог нужно определить [опцию `publicPath` в Vue CLI](https://cli.vuejs.org/ru/config/#publicpath) и соответствующее [свойство маршрутизатора `base`](../../api/#base). Также необходимо внести изменения в примерах ниже чтобы использовать вложенный каталог вместо корневого (например, заменить `RewriteBase /` на `RewriteBase /name-of-your-subfolder/`). + #### Apache ```apache diff --git a/docs/ru/guide/essentials/redirect-and-alias.md b/docs/ru/guide/essentials/redirect-and-alias.md index bcd7c5758..630b82ae0 100644 --- a/docs/ru/guide/essentials/redirect-and-alias.md +++ b/docs/ru/guide/essentials/redirect-and-alias.md @@ -35,7 +35,7 @@ const router = new VueRouter({ }) ``` -Обратите внимание, что [навигационные хуки](../advanced/navigation-guards.md) не применяются на маршруте, который служит для перенаправления, только на его цель. В приведённом ниже примере добавление хуков `beforeEnter` или `beforeLeave` на маршрут `/a` не будет иметь никакого эффекта. +Обратите внимание, что [навигационные хуки](../advanced/navigation-guards.md) не применяются на маршруте, который служит для перенаправления, только на его цель. В приведённом ниже примере добавление хуков `beforeEnter` на маршрут `/a` не будет иметь никакого эффекта. Для демонстрации более сложных возможностей, обратите внимание на [этот пример](https://github.com/vuejs/vue-router/blob/dev/examples/redirect/app.js). diff --git a/docs/zh/README.md b/docs/zh/README.md index b34b6fe9c..d790fdb42 100644 --- a/docs/zh/README.md +++ b/docs/zh/README.md @@ -1,7 +1,5 @@ # 介绍 - - :::tip 版本说明 对于 TypeScript 用户来说,`vue-router@3.0+` 依赖 `vue@2.5+`,反之亦然。 ::: diff --git a/docs/zh/api/README.md b/docs/zh/api/README.md index c099be171..3cd404cc0 100644 --- a/docs/zh/api/README.md +++ b/docs/zh/api/README.md @@ -4,8 +4,6 @@ sidebar: auto # API 参考 - - ## `` `` 组件支持用户在具有路由功能的应用中 (点击) 导航。 @@ -14,22 +12,52 @@ sidebar: auto `` 比起写死的 `` 会好一些,理由如下: - 无论是 HTML5 history 模式还是 hash 模式,它的表现行为一致,所以,当你要切换路由模式,或者在 IE9 降级使用 hash 模式,无须作任何变动。 +- 在 HTML5 history 模式下,`router-link` 会守卫点击事件,让浏览器不再重新加载页面。 +- 当你在 HTML5 history 模式下使用 `base` 选项之后,所有的 `to` 属性都不需要写 (基路径) 了。 -- 在 HTML5 history 模式下,`router-link` 会守卫点击事件,让浏览器不再重新加载页面。 +### `v-slot` API (3.1.0 新增) -- 当你在 HTML5 history 模式下使用 `base` 选项之后,所有的 `to` 属性都不需要写 (基路径) 了。 +`router-link` 通过一个[作用域插槽](https://cn.vuejs.org/v2/guide/components-slots.html#作用域插槽)暴露底层的定制能力。这是一个更高阶的 API,主要面向库作者,但也可以为开发者提供便利,多数情况用在一个类似 _NavLink_ 这样的组件里。 -### 将激活 class 应用在外层元素 +**在使用 `v-slot` API 时,需要向 `router-link` 传入一个单独的子元素**。否则 `router-link` 将会把子元素包裹在一个 `span` 元素内。 -有时候我们要让激活 class 应用在外层元素,而不是 `` 标签本身,那么可以用 `` 渲染外层元素,包裹着内层的原生 `` 标签: +```html + + {{ route.fullPath }} + +``` -``` html - - /foo +- `href`:解析后的 URL。将会作为一个 `a` 元素的 `href` attribute。 +- `route`:解析后的规范化的地址。 +- `navigate`:触发导航的函数。**会在必要时自动阻止事件**,和 `router-link` 同理。 +- `isActive`:如果需要应用[激活的 class](#active-class) 则为 `true`。允许应用一个任意的 class。 +- `isExactActive`:如果需要应用[精确激活的 class](#exact-active-class) 则为 `true`。允许应用一个任意的 class。 + +### 示例:将激活的 class 应用在外层元素 + +有的时候我们可能想把激活的 class 应用到一个外部元素而不是 `` 标签本身,这时你可以在一个 `router-link` 中包裹该元素并使用 `v-slot` property 来创建链接: + +```html + +
  • + {{ route.fullPath }} +
  • ``` -在这种情况下,`` 将作为真实的链接 (它会获得正确的 `href` 的),而 "激活时的 CSS 类名" 则设置到外层的 `
  • `。 +:::tip 提示 +如果你在 `` 元素上添加一个 `target="_blank"`,则 `@click="navigate"` 处理器会被忽略。 +::: ## `` Props @@ -40,7 +68,7 @@ sidebar: auto 表示目标路由的链接。当被点击后,内部会立刻把 `to` 的值传到 `router.push()`,所以这个值可以是一个字符串或者是描述目标位置的对象。 - ``` html + ```html Home @@ -59,7 +87,9 @@ sidebar: auto User - Register + Register ``` ### replace @@ -69,7 +99,7 @@ sidebar: auto 设置 `replace` 属性的话,当点击时,会调用 `router.replace()` 而不是 `router.push()`,于是导航后不会留下 history 记录。 - ``` html + ```html ``` @@ -80,7 +110,7 @@ sidebar: auto 设置 `append` 属性后,则在当前 (相对) 路径前添加基路径。例如,我们从 `/a` 导航到一个相对路径 `b`,如果没有配置 `append`,则路径为 `/b`,如果配了,则为 `/a/b` - ``` html + ```html ``` @@ -89,10 +119,10 @@ sidebar: auto - 类型: `string` - 默认值: `"a"` - 有时候想要 `` 渲染成某种标签,例如 `
  • `。 + 有时候想要 `` 渲染成某种标签,例如 `
  • `。 于是我们使用 `tag` prop 类指定何种标签,同样它还是会监听点击,触发导航。 - ``` html + ```html foo
  • foo
  • @@ -103,21 +133,21 @@ sidebar: auto - 类型: `string` - 默认值: `"router-link-active"` - 设置 链接激活时使用的 CSS 类名。默认值可以通过路由的构造选项 `linkActiveClass` 来全局配置。 + 设置链接激活时使用的 CSS 类名。默认值可以通过路由的构造选项 `linkActiveClass` 来全局配置。 ### exact - 类型: `boolean` - 默认值: `false` - "是否激活" 默认类名的依据是 **inclusive match** (全包含匹配)。 + “是否激活”默认类名的依据是**包含匹配**。 举个例子,如果当前的路径是 `/a` 开头的,那么 `` 也会被设置 CSS 类名。 - 按照这个规则,每个路由都会激活``!想要链接使用 "exact 匹配模式",则使用 `exact` 属性: + 按照这个规则,每个路由都会激活 ``!想要链接使用“精确匹配模式”,则使用 `exact` 属性: - ``` html + ```html - + ``` 查看更多关于激活链接类名的例子[可运行](https://jsfiddle.net/8xrk1n9f/) @@ -145,7 +175,7 @@ sidebar: auto 因为它也是个组件,所以可以配合 `` 和 `` 使用。如果两个结合一起用,要确保在内层使用 ``: -``` html +```html @@ -170,22 +200,22 @@ sidebar: auto `RouteConfig` 的类型定义: - ``` js - declare type RouteConfig = { - path: string; - component?: Component; - name?: string; // 命名路由 - components?: { [name: string]: Component }; // 命名视图组件 - redirect?: string | Location | Function; - props?: boolean | Object | Function; - alias?: string | Array; - children?: Array; // 嵌套路由 - beforeEnter?: (to: Route, from: Route, next: Function) => void; - meta?: any; + ```ts + interface RouteConfig = { + path: string, + component?: Component, + name?: string, // 命名路由 + components?: { [name: string]: Component }, // 命名视图组件 + redirect?: string | Location | Function, + props?: boolean | Object | Function, + alias?: string | Array, + children?: Array, // 嵌套路由 + beforeEnter?: (to: Route, from: Route, next: Function) => void, + meta?: any, // 2.6.0+ - caseSensitive?: boolean; // 匹配规则是否大小写敏感?(默认值:false) - pathToRegexpOptions?: Object; // 编译正则的选项 + caseSensitive?: boolean, // 匹配规则是否大小写敏感?(默认值:false) + pathToRegexpOptions?: Object // 编译正则的选项 } ``` @@ -217,7 +247,7 @@ sidebar: auto - 默认值: `"router-link-active"` - 全局配置 `` 的默认“激活 class 类名”。参考 [router-link](#router-link)。 + 全局配置 `` 默认的激活的 class。参考 [router-link](#router-link)。 ### linkExactActiveClass @@ -225,7 +255,7 @@ sidebar: auto - 默认值: `"router-link-exact-active"` - 全局配置 `` 精确激活的默认的 class。可同时翻阅 [router-link](#router-link)。 + 全局配置 `` 默认的精确激活的 class。可同时翻阅 [router-link](#router-link)。 ### scrollBehavior @@ -285,18 +315,20 @@ sidebar: auto ## Router 实例方法 ### router.beforeEach + ### router.beforeResolve + ### router.afterEach 函数签名: -``` js +```js router.beforeEach((to, from, next) => { - /* must call `next` */ + /* 必须调用 `next` */ }) router.beforeResolve((to, from, next) => { - /* must call `next` */ + /* 必须调用 `next` */ }) router.afterEach((to, from) => {}) @@ -307,14 +339,18 @@ router.afterEach((to, from) => {}) 在 2.5.0+ 这三个方法都返回一个移除已注册的守卫/钩子的函数。 ### router.push + ### router.replace + ### router.go + ### router.back + ### router.forward 函数签名: -``` js +```js router.push(location, onComplete?, onAbort?) router.push(location).then(onComplete).catch(onAbort) router.replace(location, onComplete?, onAbort?) @@ -330,7 +366,7 @@ router.forward() 函数签名: -``` js +```js const matchedComponents: Array = router.getMatchedComponents(location?) ``` @@ -340,7 +376,7 @@ const matchedComponents: Array = router.getMatchedComponents(location 函数签名: -``` js +```js const resolved: { location: Location; route: Route; @@ -357,7 +393,7 @@ const resolved: { 函数签名: -``` js +```js router.addRoutes(routes: Array) ``` @@ -367,7 +403,7 @@ router.addRoutes(routes: Array) 函数签名: -``` js +```js router.onReady(callback, [errorCallback]) ``` @@ -381,7 +417,7 @@ router.onReady(callback, [errorCallback]) 函数签名: -``` js +```js router.onError(callback) ``` @@ -409,7 +445,7 @@ router.onError(callback) - 导航守卫的参数: - ``` js + ```js router.beforeEach((to, from, next) => { // `to` 和 `from` 都是路由对象 }) @@ -417,9 +453,9 @@ router.onError(callback) - `scrollBehavior` 方法的参数: - ``` js + ```js const router = new VueRouter({ - scrollBehavior (to, from, savedPosition) { + scrollBehavior(to, from, savedPosition) { // `to` 和 `from` 都是路由对象 } }) @@ -427,47 +463,49 @@ router.onError(callback) ### 路由对象属性 -- **$route.path** +- **\$route.path** - 类型: `string` 字符串,对应当前路由的路径,总是解析为绝对路径,如 `"/foo/bar"`。 -- **$route.params** +- **\$route.params** - 类型: `Object` 一个 key/value 对象,包含了动态片段和全匹配片段,如果没有路由参数,就是一个空对象。 -- **$route.query** +- **\$route.query** - 类型: `Object` 一个 key/value 对象,表示 URL 查询参数。例如,对于路径 `/foo?user=1`,则有 `$route.query.user == 1`,如果没有查询参数,则是个空对象。 -- **$route.hash** +- **\$route.hash** - 类型: `string` 当前路由的 hash 值 (带 `#`) ,如果没有 hash 值,则为空字符串。 -- **$route.fullPath** +- **\$route.fullPath** - 类型: `string` 完成解析后的 URL,包含查询参数和 hash 的完整路径。 -- **$route.matched** +- **\$route.matched** - 类型: `Array` 一个数组,包含当前路由的所有嵌套路径片段的**路由记录** 。路由记录就是 `routes` 配置数组中的对象副本 (还有在 `children` 数组)。 - ``` js + ```js const router = new VueRouter({ routes: [ // 下面的对象就是路由记录 - { path: '/foo', component: Foo, + { + path: '/foo', + component: Foo, children: [ // 这也是个路由记录 { path: 'bar', component: Bar } @@ -479,11 +517,11 @@ router.onError(callback) 当 URL 为 `/foo/bar`,`$route.matched` 将会是一个包含从上到下的所有对象 (副本)。 -- **$route.name** +- **\$route.name** 当前路由的名称,如果有的话。(查看[命名路由](../guide/essentials/named-routes.md)) -- **$route.redirectedFrom** +- **\$route.redirectedFrom** 如果存在重定向,即为重定向来源的路由的名字。(参阅[重定向和别名](../guide/essentials/redirect-and-alias.md)) @@ -493,11 +531,11 @@ router.onError(callback) 通过在 Vue 根实例的 `router` 配置传入 router 实例,下面这些属性成员会被注入到每个子组件。 -- **this.$router** +- **this.\$router** router 实例。 -- **this.$route** +- **this.\$route** 当前激活的[路由信息对象](#路由对象)。这个属性是只读的,里面的属性是 immutable (不可变) 的,不过你可以 watch (监测变化) 它。 diff --git a/docs/zh/guide/README.md b/docs/zh/guide/README.md index 81058e1f4..b5d2ac53f 100644 --- a/docs/zh/guide/README.md +++ b/docs/zh/guide/README.md @@ -1,7 +1,5 @@ # 起步 - - ::: tip 注意 教程中的案例代码将使用 [ES2015](https://github.com/lukehoban/es6features) 来编写。 @@ -12,7 +10,7 @@ ## HTML -``` html +```html @@ -33,7 +31,7 @@ ## JavaScript -``` js +```js // 0. 如果使用模块化机制编程,导入Vue和VueRouter,要调用 Vue.use(VueRouter) // 1. 定义 (路由) 组件。 @@ -73,16 +71,14 @@ const app = new Vue({ // Home.vue export default { computed: { - username () { + username() { // 我们很快就会看到 `params` 是什么 return this.$route.params.username } }, methods: { - goBack () { - window.history.length > 1 - ? this.$router.go(-1) - : this.$router.push('/') + goBack() { + window.history.length > 1 ? this.$router.go(-1) : this.$router.push('/') } } } @@ -92,4 +88,4 @@ export default { 你可以看看这个[在线的](https://jsfiddle.net/yyx990803/xgrjzsup/)例子。 -要注意,当 `` 对应的路由匹配成功,将自动设置 class 属性值 `.router-link-active`。查看 [API 文档](../api/#router-link) 学习更多相关内容。 +要注意,当 `` 对应的路由匹配成功,将自动设置 class 属性值 `.router-link-active`。查看 [API 文档](../api/#router-link) 学习更多相关内容。 diff --git a/docs/zh/guide/advanced/data-fetching.md b/docs/zh/guide/advanced/data-fetching.md index c20e4cc67..378ece882 100644 --- a/docs/zh/guide/advanced/data-fetching.md +++ b/docs/zh/guide/advanced/data-fetching.md @@ -17,7 +17,7 @@ ``` html