From 391e204b476a17e40e032ce4060e2771bc1ba0be Mon Sep 17 00:00:00 2001 From: Daichi Date: Mon, 28 May 2018 00:32:14 +0900 Subject: [PATCH 1/2] migrating from gitbooks --- dist/vue-router.common.js | 53 +- dist/vue-router.esm.js | 53 +- dist/vue-router.js | 53 +- dist/vue-router.min.js | 6 +- docs/.vuepress/config.js | 55 ++ docs/ja/README.md | 18 + docs/ja/api/README.md | 504 ++++++++++++++++++ docs/ja/guide/README.md | 95 ++++ docs/ja/guide/advanced/data-fetching.md | 110 ++++ docs/ja/guide/advanced/lazy-loading.md | 37 ++ docs/ja/guide/advanced/meta.md | 52 ++ docs/ja/guide/advanced/navigation-guards.md | 153 ++++++ docs/ja/guide/advanced/scroll-behavior.md | 81 +++ docs/ja/guide/advanced/transitions.md | 58 ++ docs/ja/guide/essentials/dynamic-matching.md | 74 +++ docs/ja/guide/essentials/history-mode.md | 136 +++++ docs/ja/guide/essentials/named-routes.md | 31 ++ docs/ja/guide/essentials/named-views.md | 86 +++ docs/ja/guide/essentials/navigation.md | 87 +++ docs/ja/guide/essentials/nested-routes.md | 98 ++++ docs/ja/guide/essentials/passing-props.md | 75 +++ .../ja/guide/essentials/redirect-and-alias.md | 60 +++ docs/ja/installation.md | 44 ++ 23 files changed, 1932 insertions(+), 87 deletions(-) create mode 100644 docs/ja/README.md create mode 100644 docs/ja/api/README.md create mode 100644 docs/ja/guide/README.md create mode 100644 docs/ja/guide/advanced/data-fetching.md create mode 100644 docs/ja/guide/advanced/lazy-loading.md create mode 100644 docs/ja/guide/advanced/meta.md create mode 100644 docs/ja/guide/advanced/navigation-guards.md create mode 100644 docs/ja/guide/advanced/scroll-behavior.md create mode 100644 docs/ja/guide/advanced/transitions.md create mode 100644 docs/ja/guide/essentials/dynamic-matching.md create mode 100644 docs/ja/guide/essentials/history-mode.md create mode 100644 docs/ja/guide/essentials/named-routes.md create mode 100644 docs/ja/guide/essentials/named-views.md create mode 100644 docs/ja/guide/essentials/navigation.md create mode 100644 docs/ja/guide/essentials/nested-routes.md create mode 100644 docs/ja/guide/essentials/passing-props.md create mode 100644 docs/ja/guide/essentials/redirect-and-alias.md create mode 100644 docs/ja/installation.md diff --git a/dist/vue-router.common.js b/dist/vue-router.common.js index c9eb5a168..422222016 100644 --- a/dist/vue-router.common.js +++ b/dist/vue-router.common.js @@ -1,6 +1,6 @@ -/** +/*! * vue-router v3.0.1 - * (c) 2017 Evan You + * (c) 2018 Evan You * @license MIT */ 'use strict'; @@ -24,7 +24,7 @@ function isError (err) { } var View = { - name: 'router-view', + name: 'RouterView', functional: true, props: { name: { @@ -112,7 +112,7 @@ var View = { return h(component, data, children) } -}; +} function resolveProps (route, config) { switch (typeof config) { @@ -240,7 +240,6 @@ function stringifyQuery (obj) { /* */ - var trailingSlashRE = /\/?$/; function createRoute ( @@ -383,7 +382,7 @@ var toTypes = [String, Object]; var eventTypes = [String, Array]; var Link = { - name: 'router-link', + name: 'RouterLink', props: { to: { type: toTypes, @@ -418,17 +417,17 @@ var Link = { var globalExactActiveClass = router.options.linkExactActiveClass; // Support global empty active class var activeClassFallback = globalActiveClass == null - ? 'router-link-active' - : globalActiveClass; + ? 'router-link-active' + : globalActiveClass; var exactActiveClassFallback = globalExactActiveClass == null - ? 'router-link-exact-active' - : globalExactActiveClass; + ? 'router-link-exact-active' + : globalExactActiveClass; var activeClass = this.activeClass == null - ? activeClassFallback - : this.activeClass; + ? activeClassFallback + : this.activeClass; var exactActiveClass = this.exactActiveClass == null - ? exactActiveClassFallback - : this.exactActiveClass; + ? exactActiveClassFallback + : this.exactActiveClass; var compareTarget = location.path ? createRoute(null, location, null, router) : route; @@ -481,7 +480,7 @@ var Link = { return h(this.tag, data, this.$slots.default) } -}; +} function guardEvent (e) { // don't redirect with control keys @@ -559,8 +558,8 @@ function install (Vue) { get: function get () { return this._routerRoot._route } }); - Vue.component('router-view', View); - Vue.component('router-link', Link); + Vue.component('RouterView', View); + Vue.component('RouterLink', Link); var strats = Vue.config.optionMergeStrategies; // use the same hook merging strategy for route hooks @@ -1070,7 +1069,6 @@ function pathToRegexp (path, keys, options) { return stringToRegexp(/** @type {string} */ (path), /** @type {!Array} */ (keys), options) } - pathToRegexp_1.parse = parse_1; pathToRegexp_1.compile = compile_1; pathToRegexp_1.tokensToFunction = tokensToFunction_1; @@ -1266,7 +1264,6 @@ function normalizePath (path, parent, strict) { /* */ - function normalizeLocation ( raw, current, @@ -1331,6 +1328,7 @@ function assign (a, b) { /* */ + function createMatcher ( routes, router @@ -1398,8 +1396,8 @@ function createMatcher ( ) { var originalRedirect = record.redirect; var redirect = typeof originalRedirect === 'function' - ? originalRedirect(createRoute(record, location, null, router)) - : originalRedirect; + ? originalRedirect(createRoute(record, location, null, router)) + : originalRedirect; if (typeof redirect === 'string') { redirect = { path: redirect }; @@ -1526,7 +1524,6 @@ function resolveRecordPath (path, record) { /* */ - var positionStore = Object.create(null); function setupScroll () { @@ -1562,7 +1559,7 @@ function handleScroll ( // wait until re-render finishes before scrolling router.app.$nextTick(function () { var position = getScrollPosition(); - var shouldScroll = behavior(to, from, isPop ? position : null); + var shouldScroll = behavior.call(router, to, from, isPop ? position : null); if (!shouldScroll) { return @@ -2135,7 +2132,6 @@ function poll ( /* */ - var HTML5History = (function (History$$1) { function HTML5History (router, base) { var this$1 = this; @@ -2143,8 +2139,9 @@ var HTML5History = (function (History$$1) { History$$1.call(this, router, base); var expectScroll = router.options.scrollBehavior; + var supportsScroll = supportsPushState && expectScroll; - if (expectScroll) { + if (supportsScroll) { setupScroll(); } @@ -2160,7 +2157,7 @@ var HTML5History = (function (History$$1) { } this$1.transitionTo(location, function (route) { - if (expectScroll) { + if (supportsScroll) { handleScroll(router, route, current, true); } }); @@ -2223,7 +2220,6 @@ function getLocation (base) { /* */ - var HashHistory = (function (History$$1) { function HashHistory (router, base, fallback) { History$$1.call(this, router, base); @@ -2361,7 +2357,6 @@ function replaceHash (path) { /* */ - var AbstractHistory = (function (History$$1) { function AbstractHistory (router, base) { History$$1.call(this, router, base); @@ -2420,6 +2415,8 @@ var AbstractHistory = (function (History$$1) { /* */ + + var VueRouter = function VueRouter (options) { if ( options === void 0 ) options = {}; diff --git a/dist/vue-router.esm.js b/dist/vue-router.esm.js index 130c26b94..8f93194bc 100644 --- a/dist/vue-router.esm.js +++ b/dist/vue-router.esm.js @@ -1,6 +1,6 @@ -/** +/*! * vue-router v3.0.1 - * (c) 2017 Evan You + * (c) 2018 Evan You * @license MIT */ /* */ @@ -22,7 +22,7 @@ function isError (err) { } var View = { - name: 'router-view', + name: 'RouterView', functional: true, props: { name: { @@ -110,7 +110,7 @@ var View = { return h(component, data, children) } -}; +} function resolveProps (route, config) { switch (typeof config) { @@ -238,7 +238,6 @@ function stringifyQuery (obj) { /* */ - var trailingSlashRE = /\/?$/; function createRoute ( @@ -381,7 +380,7 @@ var toTypes = [String, Object]; var eventTypes = [String, Array]; var Link = { - name: 'router-link', + name: 'RouterLink', props: { to: { type: toTypes, @@ -416,17 +415,17 @@ var Link = { var globalExactActiveClass = router.options.linkExactActiveClass; // Support global empty active class var activeClassFallback = globalActiveClass == null - ? 'router-link-active' - : globalActiveClass; + ? 'router-link-active' + : globalActiveClass; var exactActiveClassFallback = globalExactActiveClass == null - ? 'router-link-exact-active' - : globalExactActiveClass; + ? 'router-link-exact-active' + : globalExactActiveClass; var activeClass = this.activeClass == null - ? activeClassFallback - : this.activeClass; + ? activeClassFallback + : this.activeClass; var exactActiveClass = this.exactActiveClass == null - ? exactActiveClassFallback - : this.exactActiveClass; + ? exactActiveClassFallback + : this.exactActiveClass; var compareTarget = location.path ? createRoute(null, location, null, router) : route; @@ -479,7 +478,7 @@ var Link = { return h(this.tag, data, this.$slots.default) } -}; +} function guardEvent (e) { // don't redirect with control keys @@ -557,8 +556,8 @@ function install (Vue) { get: function get () { return this._routerRoot._route } }); - Vue.component('router-view', View); - Vue.component('router-link', Link); + Vue.component('RouterView', View); + Vue.component('RouterLink', Link); var strats = Vue.config.optionMergeStrategies; // use the same hook merging strategy for route hooks @@ -1068,7 +1067,6 @@ function pathToRegexp (path, keys, options) { return stringToRegexp(/** @type {string} */ (path), /** @type {!Array} */ (keys), options) } - pathToRegexp_1.parse = parse_1; pathToRegexp_1.compile = compile_1; pathToRegexp_1.tokensToFunction = tokensToFunction_1; @@ -1264,7 +1262,6 @@ function normalizePath (path, parent, strict) { /* */ - function normalizeLocation ( raw, current, @@ -1329,6 +1326,7 @@ function assign (a, b) { /* */ + function createMatcher ( routes, router @@ -1396,8 +1394,8 @@ function createMatcher ( ) { var originalRedirect = record.redirect; var redirect = typeof originalRedirect === 'function' - ? originalRedirect(createRoute(record, location, null, router)) - : originalRedirect; + ? originalRedirect(createRoute(record, location, null, router)) + : originalRedirect; if (typeof redirect === 'string') { redirect = { path: redirect }; @@ -1524,7 +1522,6 @@ function resolveRecordPath (path, record) { /* */ - var positionStore = Object.create(null); function setupScroll () { @@ -1560,7 +1557,7 @@ function handleScroll ( // wait until re-render finishes before scrolling router.app.$nextTick(function () { var position = getScrollPosition(); - var shouldScroll = behavior(to, from, isPop ? position : null); + var shouldScroll = behavior.call(router, to, from, isPop ? position : null); if (!shouldScroll) { return @@ -2133,7 +2130,6 @@ function poll ( /* */ - var HTML5History = (function (History$$1) { function HTML5History (router, base) { var this$1 = this; @@ -2141,8 +2137,9 @@ var HTML5History = (function (History$$1) { History$$1.call(this, router, base); var expectScroll = router.options.scrollBehavior; + var supportsScroll = supportsPushState && expectScroll; - if (expectScroll) { + if (supportsScroll) { setupScroll(); } @@ -2158,7 +2155,7 @@ var HTML5History = (function (History$$1) { } this$1.transitionTo(location, function (route) { - if (expectScroll) { + if (supportsScroll) { handleScroll(router, route, current, true); } }); @@ -2221,7 +2218,6 @@ function getLocation (base) { /* */ - var HashHistory = (function (History$$1) { function HashHistory (router, base, fallback) { History$$1.call(this, router, base); @@ -2359,7 +2355,6 @@ function replaceHash (path) { /* */ - var AbstractHistory = (function (History$$1) { function AbstractHistory (router, base) { History$$1.call(this, router, base); @@ -2418,6 +2413,8 @@ var AbstractHistory = (function (History$$1) { /* */ + + var VueRouter = function VueRouter (options) { if ( options === void 0 ) options = {}; diff --git a/dist/vue-router.js b/dist/vue-router.js index 3285a7699..134cfadc0 100644 --- a/dist/vue-router.js +++ b/dist/vue-router.js @@ -1,6 +1,6 @@ -/** +/*! * vue-router v3.0.1 - * (c) 2017 Evan You + * (c) 2018 Evan You * @license MIT */ (function (global, factory) { @@ -28,7 +28,7 @@ function isError (err) { } var View = { - name: 'router-view', + name: 'RouterView', functional: true, props: { name: { @@ -116,7 +116,7 @@ var View = { return h(component, data, children) } -}; +} function resolveProps (route, config) { switch (typeof config) { @@ -244,7 +244,6 @@ function stringifyQuery (obj) { /* */ - var trailingSlashRE = /\/?$/; function createRoute ( @@ -387,7 +386,7 @@ var toTypes = [String, Object]; var eventTypes = [String, Array]; var Link = { - name: 'router-link', + name: 'RouterLink', props: { to: { type: toTypes, @@ -422,17 +421,17 @@ var Link = { var globalExactActiveClass = router.options.linkExactActiveClass; // Support global empty active class var activeClassFallback = globalActiveClass == null - ? 'router-link-active' - : globalActiveClass; + ? 'router-link-active' + : globalActiveClass; var exactActiveClassFallback = globalExactActiveClass == null - ? 'router-link-exact-active' - : globalExactActiveClass; + ? 'router-link-exact-active' + : globalExactActiveClass; var activeClass = this.activeClass == null - ? activeClassFallback - : this.activeClass; + ? activeClassFallback + : this.activeClass; var exactActiveClass = this.exactActiveClass == null - ? exactActiveClassFallback - : this.exactActiveClass; + ? exactActiveClassFallback + : this.exactActiveClass; var compareTarget = location.path ? createRoute(null, location, null, router) : route; @@ -485,7 +484,7 @@ var Link = { return h(this.tag, data, this.$slots.default) } -}; +} function guardEvent (e) { // don't redirect with control keys @@ -563,8 +562,8 @@ function install (Vue) { get: function get () { return this._routerRoot._route } }); - Vue.component('router-view', View); - Vue.component('router-link', Link); + Vue.component('RouterView', View); + Vue.component('RouterLink', Link); var strats = Vue.config.optionMergeStrategies; // use the same hook merging strategy for route hooks @@ -1074,7 +1073,6 @@ function pathToRegexp (path, keys, options) { return stringToRegexp(/** @type {string} */ (path), /** @type {!Array} */ (keys), options) } - pathToRegexp_1.parse = parse_1; pathToRegexp_1.compile = compile_1; pathToRegexp_1.tokensToFunction = tokensToFunction_1; @@ -1270,7 +1268,6 @@ function normalizePath (path, parent, strict) { /* */ - function normalizeLocation ( raw, current, @@ -1335,6 +1332,7 @@ function assign (a, b) { /* */ + function createMatcher ( routes, router @@ -1402,8 +1400,8 @@ function createMatcher ( ) { var originalRedirect = record.redirect; var redirect = typeof originalRedirect === 'function' - ? originalRedirect(createRoute(record, location, null, router)) - : originalRedirect; + ? originalRedirect(createRoute(record, location, null, router)) + : originalRedirect; if (typeof redirect === 'string') { redirect = { path: redirect }; @@ -1530,7 +1528,6 @@ function resolveRecordPath (path, record) { /* */ - var positionStore = Object.create(null); function setupScroll () { @@ -1566,7 +1563,7 @@ function handleScroll ( // wait until re-render finishes before scrolling router.app.$nextTick(function () { var position = getScrollPosition(); - var shouldScroll = behavior(to, from, isPop ? position : null); + var shouldScroll = behavior.call(router, to, from, isPop ? position : null); if (!shouldScroll) { return @@ -2139,7 +2136,6 @@ function poll ( /* */ - var HTML5History = (function (History$$1) { function HTML5History (router, base) { var this$1 = this; @@ -2147,8 +2143,9 @@ var HTML5History = (function (History$$1) { History$$1.call(this, router, base); var expectScroll = router.options.scrollBehavior; + var supportsScroll = supportsPushState && expectScroll; - if (expectScroll) { + if (supportsScroll) { setupScroll(); } @@ -2164,7 +2161,7 @@ var HTML5History = (function (History$$1) { } this$1.transitionTo(location, function (route) { - if (expectScroll) { + if (supportsScroll) { handleScroll(router, route, current, true); } }); @@ -2227,7 +2224,6 @@ function getLocation (base) { /* */ - var HashHistory = (function (History$$1) { function HashHistory (router, base, fallback) { History$$1.call(this, router, base); @@ -2365,7 +2361,6 @@ function replaceHash (path) { /* */ - var AbstractHistory = (function (History$$1) { function AbstractHistory (router, base) { History$$1.call(this, router, base); @@ -2424,6 +2419,8 @@ var AbstractHistory = (function (History$$1) { /* */ + + var VueRouter = function VueRouter (options) { if ( options === void 0 ) options = {}; diff --git a/dist/vue-router.min.js b/dist/vue-router.min.js index 867a9787b..8d2267464 100644 --- a/dist/vue-router.min.js +++ b/dist/vue-router.min.js @@ -1,6 +1,6 @@ -/** +/*! * vue-router v3.0.1 - * (c) 2017 Evan You + * (c) 2018 Evan You * @license MIT */ -!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):t.VueRouter=e()}(this,function(){"use strict";function t(t,e){}function e(t){return Object.prototype.toString.call(t).indexOf("Error")>-1}function r(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}}function n(t,e){for(var r in e)t[r]=e[r];return t}function o(t,e,r){void 0===e&&(e={});var n,o=r||i;try{n=o(t||"")}catch(t){n={}}for(var a in e)n[a]=e[a];return n}function i(t){var e={};return(t=t.trim().replace(/^(\?|#|&)/,""))?(t.split("&").forEach(function(t){var r=t.replace(/\+/g," ").split("="),n=Ut(r.shift()),o=r.length>0?Ut(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 a(t){var e=t?Object.keys(t).map(function(e){var r=t[e];if(void 0===r)return"";if(null===r)return Pt(e);if(Array.isArray(r)){var n=[];return r.forEach(function(t){void 0!==t&&(null===t?n.push(Pt(e)):n.push(Pt(e)+"="+Pt(t)))}),n.join("&")}return Pt(e)+"="+Pt(r)}).filter(function(t){return t.length>0}).join("&"):null;return e?"?"+e:""}function u(t,e,r,n){var o=n&&n.options.stringifyQuery,i=e.query||{};try{i=c(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:p(e,o),matched:t?s(t):[]};return r&&(a.redirectedFrom=p(r,o)),Object.freeze(a)}function c(t){if(Array.isArray(t))return t.map(c);if(t&&"object"==typeof t){var e={};for(var r in t)e[r]=c(t[r]);return e}return t}function s(t){for(var e=[];t;)e.unshift(t),t=t.parent;return e}function p(t,e){var r=t.path,n=t.query;void 0===n&&(n={});var o=t.hash;void 0===o&&(o="");var i=e||a;return(r||"/")+i(n)+o}function f(t,e){return e===Ht?t===e:!!e&&(t.path&&e.path?t.path.replace(Mt,"")===e.path.replace(Mt,"")&&t.hash===e.hash&&h(t.query,e.query):!(!t.name||!e.name)&&(t.name===e.name&&t.hash===e.hash&&h(t.query,e.query)&&h(t.params,e.params)))}function h(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?h(n,o):String(n)===String(o)})}function l(t,e){return 0===t.path.replace(Mt,"/").indexOf(e.path.replace(Mt,"/"))&&(!e.hash||t.hash===e.hash)&&d(t.query,e.query)}function d(t,e){for(var r in e)if(!(r in t))return!1;return!0}function y(t){if(!(t.metaKey||t.altKey||t.ctrlKey||t.shiftKey||t.defaultPrevented||void 0!==t.button&&0!==t.button)){if(t.currentTarget&&t.currentTarget.getAttribute){var e=t.currentTarget.getAttribute("target");if(/\b_blank\b/i.test(e))return}return t.preventDefault&&t.preventDefault(),!0}}function v(t){if(t)for(var e,r=0;r=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}}function w(t){return t.replace(/\/\//g,"/")}function x(t,e){for(var r,n=[],o=0,i=0,a="",u=e&&e.delimiter||"/";null!=(r=Qt.exec(t));){var c=r[0],s=r[1],p=r.index;if(a+=t.slice(i,p),i=p+c.length,s)a+=s[1];else{var f=t[i],h=r[2],l=r[3],d=r[4],y=r[5],v=r[6],m=r[7];a&&(n.push(a),a="");var g=null!=h&&null!=f&&f!==h,b="+"===v||"*"===v,w="?"===v||"*"===v,x=r[2]||u,k=d||y;n.push({name:l||o++,prefix:h||"",delimiter:x,optional:w,repeat:b,partial:g,asterisk:!!m,pattern:k?C(k):m?".*":"[^"+O(x)+"]+?"})}}return i-1&&(o.params[h]=r.params[h]);if(u)return o.path=L(u.path,o.params,'named route "'+a+'"'),i(u,o,n)}else if(o.path){o.params={};for(var l=0;l=t.length?r():t[o]?e(t[o],function(){n(o+1)}):n(o+1)};n(0)}function at(t){return function(r,n,o){var i=!1,a=0,u=null;ut(t,function(t,r,n,c){if("function"==typeof t&&void 0===t.cid){i=!0,a++;var s,p=pt(function(e){st(e)&&(e=e.default),t.resolved="function"==typeof e?e:Tt.extend(e),n.components[c]=e,--a<=0&&o()}),f=pt(function(t){var r="Failed to resolve async component "+c+": "+t;u||(u=e(t)?t:new Error(r),o(u))});try{s=t(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 ut(t,e){return ct(t.map(function(t){return Object.keys(t.components).map(function(r){return e(t.components[r],t.instances[r],t,r)})}))}function ct(t){return Array.prototype.concat.apply([],t)}function st(t){return t.__esModule||te&&"Module"===t[Symbol.toStringTag]}function pt(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)}}function ft(t){if(!t)if(Bt){var e=document.querySelector("base");t=(t=e&&e.getAttribute("href")||"/").replace(/^https?:\/\/[^\/]+/,"")}else t="/";return"/"!==t.charAt(0)&&(t="/"+t),t.replace(/\/$/,"")}function ht(t,e){var r,n=Math.max(t.length,e.length);for(r=0;r=0?e.slice(0,r):e)+"#"+t}function Ct(t){Wt?nt(Ot(t)):window.location.hash=t}function jt(t){Wt?ot(Ot(t)):window.location.replace(Ot(t))}function At(t,e){return t.push(e),function(){var r=t.indexOf(e);r>-1&&t.splice(r,1)}}function _t(t,e,r){var n="hash"===r?"#"+e:e;return t?w(t+"/"+n):n}var Tt,St={name:"router-view",functional:!0,props:{name:{type:String,default:"default"}},render:function(t,e){var o=e.props,i=e.children,a=e.parent,u=e.data;u.routerView=!0;for(var c=a.$createElement,s=o.name,p=a.$route,f=a._routerViewCache||(a._routerViewCache={}),h=0,l=!1;a&&a._routerRoot!==a;)a.$vnode&&a.$vnode.data.routerView&&h++,a._inactive&&(l=!0),a=a.$parent;if(u.routerViewDepth=h,l)return c(f[s],u,i);var d=p.matched[h];if(!d)return f[s]=null,c();var y=f[s]=d.components[s];u.registerRouteInstance=function(t,e){var r=d.instances[s];(e&&r!==t||!e&&r===t)&&(d.instances[s]=e)},(u.hook||(u.hook={})).prepatch=function(t,e){d.instances[s]=e.componentInstance};var v=u.props=r(p,d.props&&d.props[s]);if(v){v=u.props=n({},v);var m=u.attrs=u.attrs||{};for(var g in v)y.props&&g in y.props||(m[g]=v[g],delete v[g])}return c(y,u,i)}},$t=/[!'()*]/g,qt=function(t){return"%"+t.charCodeAt(0).toString(16)},Lt=/%2C/g,Pt=function(t){return encodeURIComponent(t).replace($t,qt).replace(Lt,",")},Ut=decodeURIComponent,Mt=/\/?$/,Ht=u(null,{path:"/"}),It=[String,Object],Vt=[String,Array],zt={name:"router-link",props:{to:{type:It,required:!0},tag:{type:String,default:"a"},exact:Boolean,append:Boolean,replace:Boolean,activeClass:String,exactActiveClass:String,event:{type:Vt,default:"click"}},render:function(t){var e=this,r=this.$router,n=this.$route,o=r.resolve(this.to,n,this.append),i=o.location,a=o.route,c=o.href,s={},p=r.options.linkActiveClass,h=r.options.linkExactActiveClass,d=null==p?"router-link-active":p,m=null==h?"router-link-exact-active":h,g=null==this.activeClass?d:this.activeClass,b=null==this.exactActiveClass?m:this.exactActiveClass,w=i.path?u(null,i,null,r):a;s[b]=f(n,w),s[g]=this.exact?s[b]:l(n,w);var x=function(t){y(t)&&(e.replace?r.replace(i):r.push(i))},k={click:y};Array.isArray(this.event)?this.event.forEach(function(t){k[t]=x}):k[this.event]=x;var R={class:s};if("a"===this.tag)R.on=k,R.attrs={href:c};else{var E=v(this.$slots.default);if(E){E.isStatic=!1;var O=Tt.util.extend;(E.data=O({},E.data)).on=k,(E.data.attrs=O({},E.data.attrs)).href=c}else R.on=k}return t(this.tag,R,this.$slots.default)}},Bt="undefined"!=typeof window,Ft=Array.isArray||function(t){return"[object Array]"==Object.prototype.toString.call(t)},Dt=q,Kt=x,Jt=E,Nt=$,Qt=new RegExp(["(\\\\.)","([\\/.])?(?:(?:\\:(\\w+)(?:\\(((?:\\\\.|[^\\\\()])+)\\))?|\\(((?:\\\\.|[^\\\\()])+)\\))([+*?])?|(\\*))"].join("|"),"g");Dt.parse=Kt,Dt.compile=function(t,e){return E(x(t,e))},Dt.tokensToFunction=Jt,Dt.tokensToRegExp=Nt;var Xt=Object.create(null),Yt=Object.create(null),Wt=Bt&&function(){var 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)}(),Gt=Bt&&window.performance&&window.performance.now?window.performance:Date,Zt=tt(),te="function"==typeof Symbol&&"symbol"==typeof Symbol.toStringTag,ee=function(t,e){this.router=t,this.base=ft(e),this.current=Ht,this.pending=null,this.ready=!1,this.readyCbs=[],this.readyErrorCbs=[],this.errorCbs=[]};ee.prototype.listen=function(t){this.cb=t},ee.prototype.onReady=function(t,e){this.ready?t():(this.readyCbs.push(t),e&&this.readyErrorCbs.push(e))},ee.prototype.onError=function(t){this.errorCbs.push(t)},ee.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)}))})},ee.prototype.confirmTransition=function(r,n,o){var i=this,a=this.current,u=function(r){e(r)&&(i.errorCbs.length?i.errorCbs.forEach(function(t){t(r)}):(t(!1,"uncaught error during route navigation:"),console.error(r))),o&&o(r)};if(f(r,a)&&r.matched.length===a.matched.length)return this.ensureURL(),u();var c=ht(this.current.matched,r.matched),s=c.updated,p=c.deactivated,h=c.activated,l=[].concat(yt(p),this.router.beforeHooks,vt(s),h.map(function(t){return t.beforeEnter}),at(h));this.pending=r;var d=function(t,n){if(i.pending!==r)return u();try{t(r,a,function(t){!1===t||e(t)?(i.ensureURL(!0),u(t)):"string"==typeof t||"object"==typeof t&&("string"==typeof t.path||"string"==typeof t.name)?(u(),"object"==typeof t&&t.replace?i.replace(t):i.push(t)):n(t)})}catch(t){u(t)}};it(l,d,function(){var t=[];it(gt(h,t,function(){return i.current===r}).concat(i.router.resolveHooks),d,function(){if(i.pending!==r)return u();i.pending=null,n(r),i.router.app&&i.router.app.$nextTick(function(){t.forEach(function(t){t()})})})})},ee.prototype.updateRoute=function(t){var e=this.current;this.current=t,this.cb&&this.cb(t),this.router.afterHooks.forEach(function(r){r&&r(t,e)})};var re=function(t){function e(e,r){var n=this;t.call(this,e,r);var o=e.options.scrollBehavior;o&&D();var i=xt(this.base);window.addEventListener("popstate",function(t){var r=n.current,a=xt(n.base);n.current===Ht&&a===i||n.transitionTo(a,function(t){o&&K(e,t,r,!0)})})}return t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e,e.prototype.go=function(t){window.history.go(t)},e.prototype.push=function(t,e,r){var n=this,o=this.current;this.transitionTo(t,function(t){nt(w(n.base+t.fullPath)),K(n.router,t,o,!1),e&&e(t)},r)},e.prototype.replace=function(t,e,r){var n=this,o=this.current;this.transitionTo(t,function(t){ot(w(n.base+t.fullPath)),K(n.router,t,o,!1),e&&e(t)},r)},e.prototype.ensureURL=function(t){if(xt(this.base)!==this.current.fullPath){var e=w(this.base+this.current.fullPath);t?nt(e):ot(e)}},e.prototype.getCurrentLocation=function(){return xt(this.base)},e}(ee),ne=function(t){function e(e,r,n){t.call(this,e,r),n&&kt(this.base)||Rt()}return t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e,e.prototype.setupListeners=function(){var t=this,e=this.router.options.scrollBehavior,r=Wt&&e;r&&D(),window.addEventListener(Wt?"popstate":"hashchange",function(){var e=t.current;Rt()&&t.transitionTo(Et(),function(n){r&&K(t.router,n,e,!0),Wt||jt(n.fullPath)})})},e.prototype.push=function(t,e,r){var n=this,o=this.current;this.transitionTo(t,function(t){Ct(t.fullPath),K(n.router,t,o,!1),e&&e(t)},r)},e.prototype.replace=function(t,e,r){var n=this,o=this.current;this.transitionTo(t,function(t){jt(t.fullPath),K(n.router,t,o,!1),e&&e(t)},r)},e.prototype.go=function(t){window.history.go(t)},e.prototype.ensureURL=function(t){var e=this.current.fullPath;Et()!==e&&(t?Ct(e):jt(e))},e.prototype.getCurrentLocation=function(){return Et()},e}(ee),oe=function(t){function e(e,r){t.call(this,e,r),this.stack=[],this.index=-1}return t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e,e.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)},e.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)},e.prototype.go=function(t){var e=this,r=this.index+t;if(!(r<0||r>=this.stack.length)){var n=this.stack[r];this.confirmTransition(n,function(){e.index=r,e.updateRoute(n)})}},e.prototype.getCurrentLocation=function(){var t=this.stack[this.stack.length-1];return t?t.fullPath:"/"},e.prototype.ensureURL=function(){},e}(ee),ie=function(t){void 0===t&&(t={}),this.app=null,this.apps=[],this.options=t,this.beforeHooks=[],this.resolveHooks=[],this.afterHooks=[],this.matcher=z(t.routes||[],this);var e=t.mode||"hash";switch(this.fallback="history"===e&&!Wt&&!1!==t.fallback,this.fallback&&(e="hash"),Bt||(e="abstract"),this.mode=e,e){case"history":this.history=new re(this,t.base);break;case"hash":this.history=new ne(this,t.base,this.fallback);break;case"abstract":this.history=new oe(this,t.base)}},ae={currentRoute:{configurable:!0}};return ie.prototype.match=function(t,e,r){return this.matcher.match(t,e,r)},ae.currentRoute.get=function(){return this.history&&this.history.current},ie.prototype.init=function(t){var e=this;if(this.apps.push(t),!this.app){this.app=t;var r=this.history;if(r instanceof re)r.transitionTo(r.getCurrentLocation());else if(r instanceof ne){var n=function(){r.setupListeners()};r.transitionTo(r.getCurrentLocation(),n,n)}r.listen(function(t){e.apps.forEach(function(e){e._route=t})})}},ie.prototype.beforeEach=function(t){return At(this.beforeHooks,t)},ie.prototype.beforeResolve=function(t){return At(this.resolveHooks,t)},ie.prototype.afterEach=function(t){return At(this.afterHooks,t)},ie.prototype.onReady=function(t,e){this.history.onReady(t,e)},ie.prototype.onError=function(t){this.history.onError(t)},ie.prototype.push=function(t,e,r){this.history.push(t,e,r)},ie.prototype.replace=function(t,e,r){this.history.replace(t,e,r)},ie.prototype.go=function(t){this.history.go(t)},ie.prototype.back=function(){this.go(-1)},ie.prototype.forward=function(){this.go(1)},ie.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]})})):[]},ie.prototype.resolve=function(t,e,r){var n=I(t,e||this.history.current,r,this),o=this.match(n,e),i=o.redirectedFrom||o.fullPath;return{location:n,route:o,href:_t(this.history.base,i,this.mode),normalizedTo:n,resolved:o}},ie.prototype.addRoutes=function(t){this.matcher.addRoutes(t),this.history.current!==Ht&&this.history.transitionTo(this.history.getCurrentLocation())},Object.defineProperties(ie.prototype,ae),ie.install=m,ie.version="3.0.1",Bt&&window.Vue&&window.Vue.use(ie),ie}); \ No newline at end of file +!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):t.VueRouter=e()}(this,function(){"use strict";function l(t){return-1=e.length?n():e[t]?r(e[t],function(){o(t+1)}):o(t+1)};o(0)}function st(r){return function(t,e,c){var s=!1,p=0,f=null;pt(r,function(r,t,n,o){if("function"==typeof r&&void 0===r.cid){s=!0,p++;var e,i=lt(function(t){var e;((e=t).__esModule||ht&&"Module"===e[Symbol.toStringTag])&&(t=t.default),r.resolved="function"==typeof t?t:C.extend(t),n.components[o]=t,--p<=0&&c()}),a=lt(function(t){var e="Failed to resolve async component "+o+": "+t;f||(f=l(t)?t:new Error(e),c(f))});try{e=r(i,a)}catch(t){a(t)}if(e)if("function"==typeof e.then)e.then(i,a);else{var u=e.component;u&&"function"==typeof u.then&&u.then(i,a)}}}),s||c()}}function pt(t,r){return ft(t.map(function(e){return Object.keys(e.components).map(function(t){return r(e.components[t],e.instances[t],e,t)})}))}function ft(t){return Array.prototype.concat.apply([],t)}var ht="function"==typeof Symbol&&"symbol"==typeof Symbol.toStringTag;function lt(r){var n=!1;return function(){for(var t=[],e=arguments.length;e--;)t[e]=arguments[e];if(!n)return n=!0,r.apply(this,t)}}var dt=function(t,e){this.router=t,this.base=function(t){if(!t)if(y){var 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=s,this.pending=null,this.ready=!1,this.readyCbs=[],this.readyErrorCbs=[],this.errorCbs=[]};function vt(t,i,a,e){var r=pt(t,function(t,e,r,n){var o=function(t,e){"function"!=typeof t&&(t=C.extend(t));return t.options[e]}(t,i);if(o)return Array.isArray(o)?o.map(function(t){return a(t,e,r,n)}):a(o,e,r,n)});return ft(e?r.reverse():r)}function yt(t,e){if(e)return function(){return t.apply(e,arguments)}}dt.prototype.listen=function(t){this.cb=t},dt.prototype.onReady=function(t,e){this.ready?t():(this.readyCbs.push(t),e&&this.readyErrorCbs.push(e))},dt.prototype.onError=function(t){this.errorCbs.push(t)},dt.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(e){r&&r(e),e&&!n.ready&&(n.ready=!0,n.readyErrorCbs.forEach(function(t){t(e)}))})},dt.prototype.confirmTransition=function(r,e,t){var n=this,o=this.current,i=function(e){l(e)&&(n.errorCbs.length?n.errorCbs.forEach(function(t){t(e)}):console.error(e)),t&&t(e)};if(O(r,o)&&r.matched.length===o.matched.length)return this.ensureURL(),i();var a=function(t,e){var r,n=Math.max(t.length,e.length);for(r=0;r=this.stack.length)){var n=this.stack[r];this.confirmTransition(n,function(){e.index=r,e.updateRoute(n)})}},t.prototype.getCurrentLocation=function(){var t=this.stack[this.stack.length-1];return t?t.fullPath:"/"},t.prototype.ensureURL=function(){},t}(dt),Ct=function(t){void 0===t&&(t={}),this.app=null,this.apps=[],this.options=t,this.beforeHooks=[],this.resolveHooks=[],this.afterHooks=[],this.matcher=D(t.routes||[],this);var e=t.mode||"hash";switch(this.fallback="history"===e&&!et&&!1!==t.fallback,this.fallback&&(e="hash"),y||(e="abstract"),this.mode=e){case"history":this.history=new mt(this,t.base);break;case"hash":this.history=new bt(this,t.base,this.fallback);break;case"abstract":this.history=new Ot(this,t.base)}},jt={currentRoute:{configurable:!0}};function At(e,r){return e.push(r),function(){var t=e.indexOf(r);-1` + +`` はルーターが使用可能になっているアプリケーションでユーザーのナビゲーションを有効にするためのコンポーネントです。対象とする location は `to` プロパティを使って指定します。デフォルトでは正しい `href` と共に `` タグとして描画しますが、 `tag` プロパティを設定することも可能です。さらに、対象のルートがアクティブの時に、そのリンクは自動的にアクティブな CSS クラスが当てられます。 + +下記の理由により `` はハードコードする `` よりも好ましいです。 + +- HTML5 history モードでも hash モードでも同じ方法で動作します。もしあなたがモードを切り替えたりする場合や、IE9 で hash モードにフォールバックする場合に、何も変更する必要はありません。 + +- HTML5 history モードにおいて、ブラウザがページのリロードをしないように `router-link` はクリックイベントに割り込みます。 + +- HTML5 history モードで `base` オプションを使っている時に、 `to` プロパティの URL にそれを含める必要がありません。 + +### 外側の要素へのアクティブクラスの適用 + +アクティブクラスを `` タグ自身よりも、外側の要素に対して適用したいことがあるでしょう。その場合、 `` を使って外側の要素を描画して、その内側に生の `` タグをラップすることができます。 + +``` html + + /foo + +``` + +この時、 `` は実際のリンクになります (そして正しい `href` が得られます)。しかし、アクティブクラスは外側の `
  • ` に適用されます。 + +## `` Props + +### to + + - 型: `string | Location` + - 必須 + + リンクする対象のルートを表します。クリックされた時に `to` プロパティの値が内部的に `router.push()` に渡されます。つまり、この値は文字列でも location を記述するオブジェクトでも構いません。 + + ``` html + + Home + + Home + + + Home + + + Home + + + Home + + + User + + + Register + ``` + +### replace + + - 型: `boolean` + - デフォルト: `false` + + `replace` プロパティを設定するとクリックされた時に `router.push()` の代わりに `router.replace()` が呼ばれます。したがって、ナビゲーションは history レコードに残りません。 + + ``` html + + ``` + +### append + + - 型: `boolean` + - デフォルト: `false` + + `append` プロパティを設定すると現在のパスに対して常に相対パスを追加します。例えば、 `/a` から相対リンクの `b` へ遷移するのを想定した時に、 `append` がない場合は `/b` に、`append` がある場合は `/a/b` になります。 + + ``` html + + ``` + +### tag + + - 型: `string` + - デフォルト: `"a"` + + しばしば `` を `
  • ` などの他のタグとして描画したい時があるでしょう。そこで、どのタグとして描画するかを指定するために `tag` プロパティを使うことができます。そして、依然ナビゲーションのためのクリックイベントを listen します。 + + ``` html + foo + +
  • foo
  • + ``` + +### active-class + + - 型: `string` + - デフォルト: `"router-link-active"` + + リンクがアクティブな時に適用されるアクティブ CSS クラスの設定です。デフォルト値はルーターコンストラクタオプションの `linkActiveClass` でグローバルに設定可能です。 + +### exact + + - 型: `boolean` + - デフォルト: `false` + + デフォルトのアクティブクラスのマッチングの振る舞いは **包含的なマッチ** です。 例えば、現在のパスが `/a/` または `/a` から始まる限りは、`` にアクティブクラスが適用されます。 + + この結果として `` は全てのルートに対してアクティブになります! リンクに対して "正確なマッチモード" を強制するために、 `exact` プロパティを使ってください。 + + ``` html + + + ``` + + アクティブリンククラスをより説明している例としてこちらの [動作](https://jsfiddle.net/8xrk1n9f/) を確認してください。 + +### event + + - 型: `string | Array` + - デフォルト: `'click'` + + リンクナビゲーションをトリガーできるイベントを指定します。 + +### exact-active-class + + - 型 `string` + - デフォルト: `"router-link-exact-active"` + + 完全一致によってリンクがアクティブになっているときに適用されるアクティブな CSS クラスを設定します。デフォルト値は `linkExactActiveClass` ルーターコンストラクタのオプション経由でグローバルに設定することもできます。 + +## `` + +`` コンポーネントは与えられたパスに対してマッチしたコンポーネントを描画する関数型コンポーネントです。`` の中で描画されるコンポーネント自身もまた、ネストされたパスに対してコンポーネントを描画するための `` を持つことができます。 + +name ではないプロパティも描画されるコンポーネントに渡されますが、ほとんどの場合ルート単位のデータはルートのパラメーターに含まれています。 + +これは普通のコンポーネントなので、 `` と `` と共に動作します。両方を同時に使用する場合は `` を内側にするようにしてください。 + +``` html + + + + + +``` + +## `` Props + +### name + + - 型: `string` + - デフォルト: `"default"` + + `` が名前を持つ時、マッチしたルートレコードの `components` オプション内で対応する名前のコンポーネントを描画します。例は [名前付きビュー](../guide/essentials/named-views.md) をご参照ください。 + +## ルーターコンストラクタオプション + +### routes + +- 型: `Array` + + `RouteConfig` の型宣言: + + ``` js + declare type RouteConfig = { + path: string; + component?: Component; + name?: string; // 名前付きルート用 + components?: { [name: string]: Component }; // 名前付き view 用 + redirect?: string | Location | Function; + props?: boolean | string | Function; + alias?: string | Array; + children?: Array; // ネストされたルート用 + beforeEnter?: (to: Route, from: Route, next: Function) => void; + meta?: any; + + // 2.6.0+ + caseSensitive?: boolean; // センシティブマッチをケースとして使用するかどうか? (デフォルト: false) + pathToRegexpOptions?: Object; // 正規表現のコンパイルとして path-to-regexp オプション + } + ``` + +### mode + +- 型: `string` + +- デフォルト: `"hash" (in browser) | "abstract" (in Node.js)` + +- 利用可能な値: `"hash" | "history" | "abstract"` + + ルーターモードの設定。 + + - `hash`: ルーティングに URL hash を使います。HTML5 History API をサポートしていないブラウザ含めて、全ての Vue がサポートしているブラウザで動作します。 + + - `history`: HTML5 History API とサーバーの設定が必要です。[HTML5 History モード](../guide/essentials/history-mode.md) を参照してください。 + + - `abstract`: 全ての JavaScript の環境で動作します。 e.g. Node.js を使ったサーバーサイド。 **もしブラウザの API が存在しない場合、ルーターは自動的にこのモードに強制されます。** + +### base + +- 型: `string` + +- デフォルト: `"/"` + + アプリケーションのベース URL です。例えば、 `/app/` 配下で完全なシングルページアプリケーションを提供する場合、 `base` は `"/app/"` の値が使われるべきです。 + +### linkActiveClass + +- 型: `string` + +- デフォルト: `"router-link-active"` + + グローバルに設定される `` のデフォルトのアクティブクラスです。こちらの [router-link](#router-link) も参照してください。 + +### linkExactActiveClass + +- 型: `string` + +- デフォルト: `"router-link-exact-active"` + + 完全一致に対してグローバルな `` デフォルトアクティブクラスを設定します。[router-link](#router-link) も参照してください。 + +### scrollBehavior + +- 型: `Function` + + シグネチャ: + + ``` + type PositionDescriptor = + { x: number, y: number } | + { selector: string } | + ?{} + + type scrollBehaviorHandler = ( + to: Route, + from: Route, + savedPosition?: { x: number, y: number } + ) => PositionDescriptor | Promise + ``` + + より詳細については [スクロールの振る舞い](../guide/advanced/scroll-behavior.md) を参照してください。 + +### parseQuery / stringifyQuery + +- 型: `Function` + + カスタムクエリ構文解析関数 / 文字列化関数を提供します。デフォルトを上書きします。 + +### fallback + +- 型: `boolean` + + ブラウザが `history.pushState` をサポートしないとき、 ルーターが `hash` モードにフォールバックかどうか制御します。デフォルトは `true` + + これを `false` に設定すると、本質的に全ての `router-link` ナビゲーションが IE9 においてフルページリフレッシュになります。これは、サーバサイドレンダリングでハッシュモードの URL が機能しないため、IE9 で動作する必要がある場合に便利です。 + +## ルーターインスタンスプロパティ + +### router.app + +- 型: `Vue インスタンス` + + `router` が注入される root の Vue インスタンス + +### router.mode + +- 型: `string` + + ルーターが使う [モード](#mode) 。 + +### router.currentRoute + +- 型: `Route` + + [ルーターオブジェクト](#ルートオブジェクト) として表される現在のルート。 + +## メソッド + +### router.beforeEach +### router.beforeResolve +### router.afterEach + +シグネチャ: + +``` js +router.beforeEach((to, from, next) => { + /* `next` を呼び出さなければならない */ +}) + +router.beforeResolve((to, from, next) => { + /* `next` を呼び出さなければならない */ +}) + +router.afterEach((to, from) => {}) +``` + + グローバルなナビゲーションガードの追加。[ナビゲーションガード](../guide/advanced/navigation-guards.md) をご参照ください。 + + 2.5.0 以降では、3 つのメソッドすべてが、登録されたガード/フックを削除する関数を返します。 + +### router.push +### router.replace +### router.go +### router.back +### router.forward + +シグネチャ: + +``` js +router.push(location, onComplete?, onAbort?) +router.replace(location, onComplete?, onAbort?) +router.go(n) +router.back() +router.forward() +``` + + プログラムによる新しい URL へのナビゲーション。 [プログラムによるナビゲーション](../guide/essentials/navigation.md) をご参照ください。 + +### router.getMatchedComponents + +シグネチャ: + +``` js +const matchedComponents: Array = router.getMatchedComponents(location?) +``` + + 現在のルートまたは提供されたロケーションにマッチしているコンポーネント (インスタンスではなく定義 / コンストラクタ) の配列を返します。これは大抵の場合データ取得を行うサーバーサイドレンダリングで使用されます。 + +### router.resolve + +シグネチャ: + +``` js +const resolved: { + location: Location; + route: Route; + href: string; +} = router.resolve(location, current?, append?) +``` + + 逆 URL 解決します。`` で使われているものと同じ形式の location が与えられた場合は、以下の解決されたプロパティを返します。 + + - `current` はデフォルトによる現在のルートです(ほとんどの場合、これを変更する必要はありません) + - `append` は `current` ルートにパスを追加できます([`router-link`](#router-link-props)と同様に) + +### router.addRoutes + +シグネチャ: + +``` js +router.addRoutes(routes: Array) +``` + + 動的にルートをルーターに追加します。引数は `routes` コンストラクタオプションで同じルート設定形式を使用する配列でなければなりません。 + +### router.onReady + +シグネチャ: + +``` js +router.onReady(callback, [errorCallback]) +``` + + このメソッドは、ルーターが初期ナビゲーションを完了したときに呼び出されるコールバックをキューに入れます。つまり、初期ルートに関連付けられているすべての非同期 enter フックと非同期コンポーネントを解決したことを意味します。 + + これは、サーバーとクライアントの両方で一貫した出力を保証するために、サーバーサイドレンダリングに役立ちます。 + + 第 2 引数 `errorCallback` は 2.4 以降でのみサポートされます。初期ルート解決がエラーの時に、呼び出されます (例: 非同期コンポーネントの解決が失敗)。 + +### router.onError + +シグネチャ: + +``` js +router.onError(callback) +``` + + ルートナビゲーション中にエラーが検出されたときに呼び出されるコールバックを登録します。エラーを呼び出すには、次のいずれかのシナリオが必要であることに注意してください: + + - エラーがルートガード関数内で同期的に投げられる; + + - エラーが補足され、ルートガード関数内で `next(err)` を呼び出すことによって非同期に処理される; + + - ルートを描画するために必須な非同期コンポーネントを解決しようとする時に発生したエラー; + +## ルートオブジェクト + +**ルートオブジェクト**は現在のアクティブなルートの状態を表現しています。現在の URL をパースした情報と、その URL とマッチした**ルートレコード**を保持しています。 + +ルートオブジェクトは変更不可です。成功した全てのナビゲーションは結果的に新たなルートオブジェクトになります。 + +ルートオブジェクトは複数の場所に存在します。 + +- コンポーネント内での `this.$route` + +- `$route` watcher コールバック内部 + +- `router.match(location)` を呼び出した時の返り値 + +- ナビゲーションガード内での第 1 引数、第 2 引数として: + + ``` js + router.beforeEach((to, from, next) => { + // `to` と `from` は両方ともルートオブジェクト + }) + ``` + +- `scrollBehavior` 関数内の第 1 引数、第 2 引数として: + + ``` js + const router = new VueRouter({ + scrollBehavior (to, from, savedPosition) { + // `to` と `from` は両方ともルートオブジェクト + } + }) + ``` + +### ルートオブジェクトプロパティ + +- **$route.path** + + - 型: `string` + + 現在のルートのパスに等しい文字列。常に絶対パスとして解釈されます。e.g. `"/foo/bar"` + +- **$route.params** + + - 型: `Object` + + 動的セグメントとスターセグメントの key/value ペアを保持するオブジェクト。もしパラメーターがない場合、この値は空オブジェクトになります。 + +- **$route.query** + + - 型: `Object` + + クエリ文字列の key/value ペアを保持するオブジェクト。例えば `/foo?user=1` というパスの場合、`$route.query.user == 1` となります。もしクエリがない場合は、この値は空オブジェクトになります。 + +- **$route.hash** + + - 型: `string` + + hash がある時の現在のルートの hash (# 有り) です。もし hash がない場合、この値は空オブジェクトになります。 + +- **$route.fullPath** + + - 型: `string` + + クエリや hash を含む完全に解決された URL です。 + +- **$route.matched** + + - 型: `Array` + + 現在のルートのネストされた全パスセグメントに対しての **ルートレコード** を保持している配列です。ルートレコードは `routes` 設定の配列 (と `children` 配列) 内のオブジェクトのコピーです。 + + ``` js + const router = new VueRouter({ + routes: [ + // 以下のオブジェクトがルートレコード + { path: '/foo', component: Foo, + children: [ + // こちらもルートレコード + { path: 'bar', component: Bar } + ] + } + ] + }) + ``` + + URL が `/foo/bar` である時、 `$route.matched` は親から子の順番で両方の (クローンされた) オブジェクトを含む配列になります。 + +- **$route.name** + + 名前がある場合の現在のルートの名前です。(詳しくは [名前付きルート](../guide/essentials/named-routes.md) をご参照ください) + +- **$route.redirectedFrom** + + もしあれば、リダイレクト元の名前。(参照[リダイレクトとエイリアス](../guide/essentials/redirect-and-alias.md)) + +## コンポーネント注入 + +### 注入されるプロパティ + +ルーターインスタンスを root インスタンスに `router` オプションとして渡すことによって、全ての子コンポーネントに以下のプロパティが注入されます。 + +- **this.$router** + + ルーターインスタンス + +- **this.$route** + + 現在のアクティブな [ルート](#ルートオブジェクト) 。このプロパティは読み出しのみ可能かつ変更不可ですが、watch は可能です。 + +### 有効になるオプション + +- **beforeRouteEnter** +- **beforeRouteUpdate** +- **beforeRouteLeave** + + [コンポーネント内ガード](../guide/advanced/navigation-guards.md#コンポーネント内ガード) をご参照ください。 diff --git a/docs/ja/guide/README.md b/docs/ja/guide/README.md new file mode 100644 index 000000000..65ae1153c --- /dev/null +++ b/docs/ja/guide/README.md @@ -0,0 +1,95 @@ +# はじめに + +::: tip Note + ガイド内のコードのサンプルは [ES2015](https://github.com/lukehoban/es6features) を使っています。 + +すべての example では、vue の完全バージョンを使用してテンプレートを解析可能にしています。詳細は[こちら](https://jp.vuejs.org/v2/guide/installation.html#ランタイム-コンパイラとランタイム限定の違い)を参照してください。 +::: + +Vue.js と vue-router を使ったシングルページアプリケーションの構築は驚くほど簡単です。Vue.js のコンポーネントを使ってアプリケーションを既に構成しています。vue-router を混ぜ込むには、コンポーネントとルートをマッピングさせて vue-router にどこで描画するかを知らせるだけです。以下が基本的な例です。 + +## HTML + +``` html + + + +
    +

    Hello App!

    +

    + + + + Go to Foo + Go to Bar +

    + + + +
    +``` + +## JavaScript + +``` js +// 0. モジュールシステムを使っている場合 (例: vue-cli 経由で)、Vue と VueRouter をインポートし、`Vue.use(VueRouter)` を呼び出します。 + +// 1. ルートコンポーネントを定義します +// 他のファイルからインポートすることもできます +const Foo = { template: '
    foo
    ' } +const Bar = { template: '
    bar
    ' } + +// 2. ルートをいくつか定義します +// 各ルートは 1 つのコンポーネントとマッピングされる必要があります。 +// このコンポーネントは実際の `Vue.extend()`、 +// またはコンポーネントオプションのオブジェクトでも構いません。 +// ネストされたルートに関しては後で説明します +const routes = [ + { path: '/foo', component: Foo }, + { path: '/bar', component: Bar } +] + +// 3. ルーターインスタンスを作成して、ルートオプションを渡します +// 追加のオプションをここで指定できますが、 +// この例ではシンプルにしましょう +const router = new VueRouter({ + routes // `routes: routes` の短縮表記 +}) + +// 4. root となるインスタンスを作成してマウントします +// アプリケーション全体がルーターを認知できるように、 +// ルーターをインジェクトすることを忘れないでください。 +const app = new Vue({ + router +}).$mount('#app') + +// これで開始です! +``` + +ルーターを注入することによって、`this.$router` と同様、任意のコンポーネント内部で現在のルートを `this.$route` としてアクセスすることができます: + +```js +// Home.vue +export default { + computed: { + username () { + // `params` が表示される + return this.$route.params.username + } + }, + methods: { + goBack () { + window.history.length > 1 + ? this.$router.go(-1) + : this.$router.push('/') + } + } +} +``` + +ドキュメントを通して、しばしば `router` インスタンスを使用することがよくあります。`this.$router` は `router` を使用するのと全く同じです。`this.$router` を使用する理由は、ルーティング操作する必要がある全てのコンポーネントにルーターをインポートしたくないからです。 + +[動作](https://jsfiddle.net/yyx990803/xgrjzsup/) の例も確認してみてください. + +`` は対象のルートがマッチした時に自動的に `.router-link-active` が付与されるのにお気づきでしょうか。 +より詳細については [API リファレンス](../api/router-link.md) をご参照ください。 diff --git a/docs/ja/guide/advanced/data-fetching.md b/docs/ja/guide/advanced/data-fetching.md new file mode 100644 index 000000000..22244af65 --- /dev/null +++ b/docs/ja/guide/advanced/data-fetching.md @@ -0,0 +1,110 @@ +# データ取得 + +ルートが有効化された時にサーバーからデータを取得する必要がしばしばあります。例えば、ユーザープロフィールを描画する前に、サーバーからユーザーデータを取得する必要があります。これを実現するためには 2 種類の方法があります。 + +- **ナビゲーション後の取得**: ナビゲーションを先に実行し、その後次に入ってくるコンポーネントのライフサイクルフック内でデータを取得します。データ取得中にローディングを表示します。 + +- **ナビゲーション前の取得**: ルートに入るガード内でナビゲーション前にデータ取得をします。そして、データ取得後にナビゲーションを実行します。 + +技術的にはどちらも正当な選択肢です。究極的にはあなたが目指しているユーザーエクスペリエンスに依存します。 + +## ナビゲーション後の取得 + +このアプローチを取る時は次に来るコンポーネントが即座にナビゲーションされ、描画されます。そして、コンポーネントの `created` フックの中でデータを取得します。この方法ではネットワーク越しにデータを取得している間にローディング状態を表示する機会があります。また、各 view に対して、異なるローディングの対応をすることもできます。 + +`$route.params.id` を元にポストのデータを取得する必要がある `Post` コンポーネントを想定してみましょう。 + +``` html + +``` + +``` js +export default { + data () { + return { + loading: false, + post: null, + error: null + } + }, + created () { + // view が作られた時にデータを取得し、 + // そのデータは既に監視されています + this.fetchData() + }, + watch: { + // ルートが変更されたらこのメソッドを再び呼び出します + '$route': 'fetchData' + }, + methods: { + fetchData () { + this.error = this.post = null + this.loading = true + // `getPost` をあなたのデータ取得用 util や API ラッパーに置き換えてください + getPost(this.$route.params.id, (err, post) => { + this.loading = false + if (err) { + this.error = err.toString() + } else { + this.post = post + } + }) + } + } +} +``` + +## ナビゲーション前の取得 + +こちらのアプローチでは新しいルートへ実際にナビゲーションする前にデータを取得します。次に入ってくるコンポーネント内の `beforeRouteEnter` ガードでデータ取得を実行できます。データ取得が完了したら `next` を呼ぶだけです。 + +``` js +export default { + data () { + return { + post: null, + error: null + } + }, + beforeRouteEnter (route, redirect, next) { + getPost(route.params.id, (err, post) => { + next(vm => vm.setData(err, post)) + }) + }, + // コンポーネントが既に描画されている際のルート変更時は + // ロジックが少し異なります + beforeRouteUpdate (to, from, next) { + this.post = null + getPost(to.params.id, (err, post) => { + this.setData(err, post) + next() + }) + }, + methods: { + setData (err, post) { + if (err) { + this.error = err.toString() + } else { + this.post = post + } + } + } +} +``` + +次に入ってくる view へのリソースを取得している間、ユーザーは前の view に滞在します。したがって、データ取得中にプログレスバーや何らかの指標を表示することをオススメします。また、もしデータ取得が失敗した場合、何かグローバルな警告メッセージのようなものを表示する必要があります。 diff --git a/docs/ja/guide/advanced/lazy-loading.md b/docs/ja/guide/advanced/lazy-loading.md new file mode 100644 index 000000000..fee21f2a5 --- /dev/null +++ b/docs/ja/guide/advanced/lazy-loading.md @@ -0,0 +1,37 @@ +# 遅延ローディングルート + +バンドラーを使ってアプリケーションを構築している時、バンドルされる JavaScript が非常に大きいものになり得ます。結果的にページのロード時間に影響を与えてしまいます。もし各ルートコンポーネントごとに別々のチャンクにして、訪れたルートの時だけロードできればより効率的でしょう。 + +Vue の [非同期コンポーネント機能](http://jp.vuejs.org/guide/components.html#非同期コンポーネント) と webpack の [コード分割機能](https://webpack.js.org/guides/code-splitting-async/) を組み合わせることでとても簡単に遅延ロードするルートコンポーネントができます。 + +最初に、非同期コンポーネントは Promise (コンポーネント自身解決する必要がある) を返すファクトリ関数として定義できます: + +``` js +const Foo = () => Promise.resolve({ /* component definition */ }) +``` + +次に、webpack 2 において [動的 import](https://github.com/tc39/proposal-dynamic-import) 構文を使用して、コード分割ポイントを示すことができます: + +``` js +import('./Foo.vue') // returns a Promise +``` + +> Note: Babel を使用している場合、Babel が構文を正しく解析するために [syntax-dynamic-import](https://babeljs.io/docs/plugins/syntax-dynamic-import/) プラグインを追加する必要があります。 + +2 つを組み合わせることで、これは、webpack によって自動的にコード分割される非同期コンポーネントを定義する方法です: + +``` js +const Foo = () => import('./Foo.vue') +``` + +## 同じチャンク内でのコンポーネントグループ化 + +しばしば同じ非同期のチャンクに、そのルート配下のネストされた全てのコンポーネントをグループ化したいと思うかもしれません。それを実現するためには、 特別なコメント構文 (webpack > 2.4 必須)を使用してチャンクの名前を提供する [名前付きチャンク](https://webpack.js.org/guides/code-splitting-async/#chunk-names) を使う必要があります。 + +``` js +const Foo = () => import(/* webpackChunkName: "group-foo" */ './Foo.vue') +const Bar = () => import(/* webpackChunkName: "group-foo" */ './Bar.vue') +const Baz = () => import(/* webpackChunkName: "group-foo" */ './Baz.vue') +``` + +webpack は同じチャンク名のどんな非同期のモジュールも同じ非同期のチャンクにグループします。 diff --git a/docs/ja/guide/advanced/meta.md b/docs/ja/guide/advanced/meta.md new file mode 100644 index 000000000..b7f876e65 --- /dev/null +++ b/docs/ja/guide/advanced/meta.md @@ -0,0 +1,52 @@ +# ルートメタフィールド + +ルートの定義をする際に `meta` フィールドを含めることができます。 + +``` js +const router = new VueRouter({ + routes: [ + { + path: '/foo', + component: Foo, + children: [ + { + path: 'bar', + component: Bar, + // メタフィールド + meta: { requiresAuth: true } + } + ] + } + ] +}) +``` + +ではどのように `meta` フィールドにアクセスしましょう? + +まず、 `routes` 設定の中の各ルートオブジェクトは**ルートレコード**と呼ばれます。ルートレコードはネストされているかもしれません。したがって、ルートがマッチした時に、潜在的には 1 つ以上のルートレコードがマッチされる可能性があります。 + +例えば上記のルート設定で、 `/foo/bar` という URL は親のルートレコードにも子のルートレコードにもマッチします。 + +ルートにマッチした全てのルートレコードは `$route.matched` 配列として `$route` オブジェクト上で (また、ナビゲーションガード上のルートオブジェクトでも) アクセス可能になります。 + +メタフィールドをグローバルナビゲーションガードで確認するユースケースの例: + +``` js +router.beforeEach((to, from, next) => { + if (to.matched.some(record => record.meta.requiresAuth)) { + // このルートはログインされているかどうか認証が必要です。 + // もしされていないならば、ログインページにリダイレクトします。 + if (!auth.loggedIn()) { + next({ + path: '/login', + query: { redirect: to.fullPath } + }) + } else { + next() + } + } else { + next() // next() を常に呼び出すようにしてください! + } +}) + +``` diff --git a/docs/ja/guide/advanced/navigation-guards.md b/docs/ja/guide/advanced/navigation-guards.md new file mode 100644 index 000000000..7a1384e70 --- /dev/null +++ b/docs/ja/guide/advanced/navigation-guards.md @@ -0,0 +1,153 @@ +# ナビゲーションガード + +この名前が示すように、 `vue-router` によって提供されるナビゲーションガードは、リダイレクトもしくはキャンセルによって遷移をガードするために主に使用されます。ルートナビゲーション処理 (グローバル、ルート単位、コンポーネント内) をフックする多くの方法があります。 + +**パラメータまたはクエリの変更は enter/leave ナビゲーションガードをトリガーしない** ということを覚えておいてください。それらの変更に対応するために [`$route` オブジェクトを監視する](../essentials/dynamic-matching.md#reacting-to-params-changes)、またはコンポーネント内ガード `beforeRouteUpdate` を使用するかの、どちらかができます。 + +## グローバルガード + +`router.beforeEach` を使ってグローバル before ガードを登録できます。 + +``` js +const router = new VueRouter({ ... }) + +router.beforeEach((to, from, next) => { + // ... +}) +``` + +いつナビゲーションがトリガーされようとも、グローバル before ガードは作られた順番で呼び出されます。ガードは非同期に解決されるかもしれません。そしてそのナビゲーションは全てのフックが解決されるまで **未解決状態** として扱われます。 + +全てのガード関数は 3 つの引数を受け取ります。 + + - **`to: Route`**: 次にナビゲーションされる対象の [ルートオブジェクト](../../api/#ルートオブジェクト)。 + + - **`from: Route`**: ナビゲーションされる前の現在のルートです。 + + - **`next: Function`**: フックを **解決** するためにこの関数を呼ぶ必要があります。この振る舞いは `next` に渡される引数に依存します: + + - **`next()`**: パイプラインの次のフックに移動します。もしフックが残っていない場合は、このナビゲーションは **確立** されます。 + + - **`next(false)`**: 現在のナビゲーションを中止します。もしブラウザのURLが変化した場合は(ユーザーが手動で変更した場合でも、戻るボタンの場合でも)、 `from` ルートのURLにリセットされます。 + + - **`next('/')` または `next({ path: '/' })`**: 異なる場所へリダイレクトします。現在のナビゲーションは中止され、あたらしいナビゲーションが始まります。任意のロケーションオブジェクトを `next` に渡すことができます。この `next` には、`replace: true`、 `name: 'home'` のようなオプション、そして [`router-link`、`to` プロパティ](../../api/#router-link)または [`router.push`](../../api/#ルーターインスタンスプロパティ)で使用される任意のオプションを指定することができます。 + + - **`next(error)`**: (2.4.0+) `next` に渡された引数が `Error` インスタンスである場合、ナビゲーションは中止され、エラーは `router.onError()` を介して登録されたコールバックに渡されます。 + + **常に `next` 関数を呼び出すようにしてください。そうでなければ、フックは決して解決されません。** + +## グローバル解決ガード + +> New in 2.5.0 + +2.5.0 以降では、`router.beforeResolve` によってグローバルガードを登録できます。これは `router.beforeEach` に似ていますが、**すべてのコンポーネント内ガードと非同期ルートコンポーネントが解決された後**、ナビゲーションが解決される直前に解決ガードが呼び出されるという違いがあります。 + +## グローバルな After フック + +グローバル after フックを登録することもできます。しかしながら、ガードとは異なり、これらのフックは `next` 関数を受け取らず、ナビゲーションに影響しません。 + +``` js +router.afterEach((to, from) => { + // ... +}) +``` + +## ルート単位ガード + +直接ルート設定オブジェクトの `beforeEnter` ガードを定義することができます。 + +``` js +const router = new VueRouter({ + routes: [ + { + path: '/foo', + component: Foo, + beforeEnter: (to, from, next) => { + // ... + } + } + ] +}) +``` + +これらのガードはグローバル before ガードと全く同じシグネチャを持ちます。 + +### コンポーネント内ガード + +最後に、 以下のオプションでルートコンポーネント(ルータ設定に渡されるもの)の内側でルートナビゲーションガードを直接定義することができます。 + +- `beforeRouteEnter` +- `beforeRouteUpdate` (2.2 で追加) +- `beforeRouteLeave` + +``` js +const Foo = { + template: `...`, + beforeRouteEnter (to, from, next) { + // このコンポーネントを描画するルートが確立する前に呼ばれます。 + // `this` でのこのコンポーネントへのアクセスはできません。 + // なぜならばこのガードが呼び出される時にまだ作られていないからです! + }, + beforeRouteUpdate (to, from, next) { + // このコンポーネントを描画するルートが変更されたときに呼び出されますが、 + // このコンポーネントは新しいルートで再利用されます。 + // たとえば、動的な引数 `/foo/:id` を持つルートの場合、`/foo/1` と `/foo/2` の間を移動すると、 + // 同じ `Foo` コンポーネントインスタンスが再利用され、そのときにこのフックが呼び出されます。 + // `this` でコンポーネントインスタンスにアクセスできます。 + }, + beforeRouteLeave (to, from, next) { + // このコンポーネントを描画するルートが間もなく + // ナビゲーションから離れていく時に呼ばれます。 + // `this` でのコンポーネントインスタンスへのアクセスができます。 + } +} +``` + +この `beforeRouteEnter` ガードは `this` へのアクセスは**できない**です。なぜならば、ナビゲーションが確立する前にガードが呼び出されるからです。したがって、新しく入ってくるコンポーネントはまだ作られていないです。 + +しかしながら、 `next` にコールバックを渡すことでインスタンスにアクセスすることができます。このコールバックはナビゲーションが確立した時に呼ばれ、コンポーネントインスタンスはそのコールバックの引数として渡されます。 + +``` js +beforeRouteEnter (to, from, next) { + next(vm => { + // `vm` を通じてコンポーネントインスタンスにアクセス + }) +} +``` + +コールバックを `next` に渡すことをサポートするのは、`beforeRouteEnter` ガードだけであるということに注意してください。`beforeRouteUpdate` と `beforeRouteLeave` の場合、 `this` は既に利用可能です。したがって、コールバックを渡す必要はないので、*サポートされません*: + +```js +beforeRouteUpdate (to, from, next) { + // `this` を使用 + this.name = to.params.name + next() +} +``` + +**leave ガード**は、通常、ユーザが保存されていない編集内容で誤って経路を離れるのを防ぐために使用されます。ナビゲーションは `next(false)` を呼び出すことで取り消すことができます。 + +```js +beforeRouteLeave (to, from , next) { + const answer = window.confirm('Do you really want to leave? you have unsaved changes!') + if (answer) { + next() + } else { + next(false) + } +} +``` + +## 完全なナビゲーション解決フロー +1. ナビゲーションがトリガされる +2. 非アクティブ化されたコンポーネントで leave ガードを呼ぶ +3. グローバル `beforeEach` ガードを呼ぶ +4. 再利用されるコンポーネントで `beforeRouteUpdate` ガードを呼ぶ (2.2 以降) +5. ルート設定内の `beforeEnter` を呼ぶ +6. 非同期ルートコンポーネントを解決する +7. アクティブ化されたコンポーネントで `beforeRouteEnter` を呼ぶ +8. グローバル `beforeResolve` ガードを呼ぶ (2.5 以降) +9. ナビゲーションが確定される +10. グローバル `afterEach` フックを呼ぶ +11. DOM 更新がトリガされる +12. インスタンス化されたインスンタンスによって `beforeRouteEnter` ガードで `next` に渡されたコールバックを呼ぶ diff --git a/docs/ja/guide/advanced/scroll-behavior.md b/docs/ja/guide/advanced/scroll-behavior.md new file mode 100644 index 000000000..ed6035599 --- /dev/null +++ b/docs/ja/guide/advanced/scroll-behavior.md @@ -0,0 +1,81 @@ +# スクロールの振る舞い + +クライアントサイドのルーティングを使っている時に、新しいルートに対してスクロールをトップへ移動させたいかもしれません、もしくは実際のページリロードがしているように history 要素のスクロールポジションを保持したいこともあるかもしれません。 `vue-router` ではこれらをさらによく実現できます。ルートナビゲーションにおけるスクロールの挙動を完全にカスタマイズすることができます。 + +**注意: この機能は ブラウザが `history.pushState` をサポートしている場合のみ動作します。** + +ルーターインスタンスを作る時に、 `scrollBehavior` 関数を提供できます。 + +``` js +const router = new VueRouter({ + routes: [...], + scrollBehavior (to, from, savedPosition) { + // 望みのポジションを返す + } +}) +``` + +`scrollBehavior` 関数は `to` と `from` のルートオブジェクトを受け取ります。第 3 引数の `savedPosition` は `popstate` ナビゲーション (ブラウザの戻る/進むボタンがトリガーされた) 時のみ利用可能です。 + +この関数はスクロールポジションオブジェクトを返すことができます。そのオブジェクトは以下のような形式です。 + +- `{ x: number, y: number }` +- `{ selector: string }` +- `{ selector: string, offset? : { x: number, y: number }}` (2.6.0 以降においてだけ offset はサポート) + +もし falsy な値や空のオブジェクトが返った場合、何もスクロールは起きません。 + +例: + +``` js +scrollBehavior (to, from, savedPosition) { + return { x: 0, y: 0 } +} +``` + +これは単純に全てのルートナビゲーションに対してページスクロールをトップにします。 + +`savedPosition` を返すことは結果的に戻る/進むボタンを押してナビゲーションした時にネイティブのような挙動になります。 + +``` js +scrollBehavior (to, from, savedPosition) { + if (savedPosition) { + return savedPosition + } else { + return { x: 0, y: 0 } + } +} +``` + +もし"アンカーへスクロール"の振る舞いをシミュレートしたい場合は以下のようにしてください。 + +``` js +scrollBehavior (to, from, savedPosition) { + if (to.hash) { + return { + selector: to.hash + // , offset: { x: 0, y: 10 } + } + } +} +``` + +きめの細かいスクロールの挙動コントロールを実装するために [ルートメタフィールド](meta.md) も利用可能です。詳細な例は [こちら](https://github.com/vuejs/vue-router/blob/dev/examples/scroll-behavior/app.js) をご参照ください。 + +## 非同期なスクローリング + +> 2.8.0 で新規 + +期待する位置記述子 (position descriptor) に解決されるプロミスを返すこともできます: + +``` js +scrollBehavior (to, from, savedPosition) { + return new Promise((resolve, reject) => { + setTimeout(() => { + resolve({ x: 0, y: 0 }) + }, 500) + }) +} +``` + +スクロールの振る舞いをページの遷移とうまく合わせるために、ページレベルのトランジションコンポーネントからのイベントにフックすることは可能ですが、ユースケースにおいて可能性のある食い違いと複雑さのために、単純に特定のユーザランド実装を可能にするために、このプリミティブな機能を提供します。 diff --git a/docs/ja/guide/advanced/transitions.md b/docs/ja/guide/advanced/transitions.md new file mode 100644 index 000000000..18654c40d --- /dev/null +++ b/docs/ja/guide/advanced/transitions.md @@ -0,0 +1,58 @@ +# トランジション + +基本的に `` は動的コンポーネントなので、 `` コンポーネントを使うのと同じ方法でトランジションを適用することができます。 + +``` html + + + +``` + +[`` についての全て](http://jp.vuejs.org/guide/transitions.html) はここでも動作します。 + +## ルート単位のトランジション + +上記の使い方では全てのトランジションが全てのルートに対して適用されます。もし各ルートコンポーネントにそれぞれ違うトランジションを持たせたい場合は、代わりにルーターコンポーネント内で異なる名前で `` を使うことができます。 + +``` js +const Foo = { + template: ` + +
    ...
    +
    + ` +} + +const Bar = { + template: ` + +
    ...
    +
    + ` +} +``` + +## ルートベースの動的トランジション + +対象のルートと現在のルートの関係を元に動的にトランジションを決定することも可能です。 + +``` html + + + + +``` + +``` js +// そして親コンポーネントの中で、 +// `$route` を watch して使用するトランジションを決定します +watch: { + '$route' (to, from) { + const toDepth = to.path.split('/').length + const fromDepth = from.path.split('/').length + this.transitionName = toDepth < fromDepth ? 'slide-right' : 'slide-left' + } +} +``` + +完全な例は [こちら](https://github.com/vuejs/vue-router/blob/dev/examples/transitions/app.js) をご参照ください。 diff --git a/docs/ja/guide/essentials/dynamic-matching.md b/docs/ja/guide/essentials/dynamic-matching.md new file mode 100644 index 000000000..55d849e37 --- /dev/null +++ b/docs/ja/guide/essentials/dynamic-matching.md @@ -0,0 +1,74 @@ +# 動的ルートマッチング + +パターンを使って同じコンポーネントにルートをマップする必要がしばしばあるでしょう。例えば、 `User` コンポーネントは全てのユーザーに対して描画されるべきであるが、それぞれ異なるユーザー ID を持つ場合などです。`vue-router` ではパスの中の動的なセグメントを使用して実現できます。 + +``` js +const User = { + template: '
    User
    ' +} + +const router = new VueRouter({ + routes: [ + // コロンで始まる動的セグメント + { path: '/user/:id', component: User } + ] +}) +``` + +これで `/user/foo` や `/user/bar` などの URL 両方とも同じルートにマッチします。 + +動的セグメントはコロン `:` を使って表されます。ルートがマッチした時、この動的セグメントの値は全てのコンポーネント内で `this.$route.params` として利用可能になります。したがって、現在の `User` のテンプレートを次のように更新することで現在のユーザー ID を表示することができます。 + +``` js +const User = { + template: '
    User {{ $route.params.id }}
    ' +} +``` + +[こちら](https://jsfiddle.net/yyx990803/4xfa2f19/) のデモの例も確認してみてください。 + +1 つのルートが複数の動的なセグメントを持つこともできます。そして、それらは `$route.params` の一致したフィールドとマップされます。例: + +| パターン | マッチしたパス | $route.params | +|---------|------|--------| +| /user/:username | /user/evan | `{ username: 'evan' }` | +| /user/:username/post/:post_id | /user/evan/post/123 | `{ username: 'evan', post_id: 123 }` | + +`$route.params` に加えて、`$route` オブジェクトでは `$route.query` (もし URL 上にクエリがあるなら) や `$route.hash` など便利な情報も利用可能です。それらの詳細については [API リファレンス](../api/route-object.md) でご確認ください。 + +## パラメーター変更の検知 + +ルートのパラメーターを使う際に特筆すべき点は、ユーザーが `/user/foo` から `/user/bar` へ遷移するときに**同じコンポーネントインスタンスが再利用される**ということです。 両方のルートが同じコンポーネントを描画するため、古いインスタンスを破棄して新しいものを生成するよりも効率的です。**しかしながら、これはコンポーネントのライフサイクルフックが呼ばれないことを意味しています。** + +同じコンポーネントでパラメーター変更を検知するためには、 `$route` オブジェクトを watch するだけです。 + +``` js +const User = { + template: '...', + watch: { + '$route' (to, from) { + // ルートの変更の検知... + } + } +} +``` + +または、2.2 で導入された `beforeRouteUpdate` ガードを使用します: + +``` js +const User = { + template: '...', + beforeRouteUpdate (to, from, next) { + // ルート変更に反応する... + // next() を呼び出すのを忘れないでください + } +} +``` + +## 高度なマッチングパターン + +`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) をご参照ください。 + +## マッチングの優先度 + +しばしば同じURLで複数のルートがマッチすることがあります。そのようなケースではマッチングの優先度はルートの定義された順番によって決定されます。先に定義されたルートほど優先度が高くなります。 diff --git a/docs/ja/guide/essentials/history-mode.md b/docs/ja/guide/essentials/history-mode.md new file mode 100644 index 000000000..e00986b81 --- /dev/null +++ b/docs/ja/guide/essentials/history-mode.md @@ -0,0 +1,136 @@ +# HTML5 History モード + +`vue-router` のデフォルトは _hash モード_ です - 完全な URL を hash を使ってシミュレートし、 URL が変更された時にページのリロードが起きません。 + +その hash を取り除くために、ページのリロード無しに URL 遷移を実現する `history.pushState` API を利用したルーターの **history モード** を使うことができます。 + +``` js +const router = new VueRouter({ + mode: 'history', + routes: [...] +}) +``` + +history モードを使用する時は、URL は "普通" に見えます e.g. `http://oursite.com/user/id`。美しいですね! + +しかしながら一点問題があります。シングルページのクライアントサイドアプリケーションなので、適切なサーバーの設定をしないと、ユーザーがブラウザで直接 `http://oursite.com/user/id` にアクセスした場合に 404 エラーが発生します。 + +心配する必要はありません。この問題を直すためには、単純な catch-all フォールバックのためのルートをサーバー側で追加するだけです。もし URL がどの静的なアセットにもマッチしなかった時はあなたのアプリケーションが動作しているのと同じ `index.html` ページで受け付けましょう。これも美しいですね! + +## サーバーの設定例 + +#### Apache + +```apache + + RewriteEngine On + RewriteBase / + RewriteRule ^index\.html$ - [L] + RewriteCond %{REQUEST_FILENAME} !-f + RewriteCond %{REQUEST_FILENAME} !-d + RewriteRule . /index.html [L] + +``` + +#### nginx + +```nginx +location / { + try_files $uri $uri/ /index.html; +} +``` + +#### Native Node.js + +```js +const http = require('http') +const fs = require('fs') +const httpPort = 80 + +http.createServer((req, res) => { + fs.readFile('index.htm', 'utf-8', (err, content) => { + if (err) { + console.log('We cannot open "index.htm" file.') + } + + res.writeHead(200, { + 'Content-Type': 'text/html; charset=utf-8' + }) + + res.end(content) + }) +}).listen(httpPort, () => { + console.log('Server listening on: http://localhost:%s', httpPort) +}) +``` + +#### Node.js (Express) + +Node.js/Express では [connect-history-api-fallback middleware](https://github.com/bripkens/connect-history-api-fallback) の利用を検討してください。 + +#### Internet Information Services (IIS) + +1. [IIS UrlRewrite](https://www.iis.net/downloads/microsoft/url-rewrite) をインストール +2. 以下によるサイトのルートディレクトリに `web.config` ファイルを作成 + +``` xml + + + + + + + + + + + + + + + + + +``` + +#### Caddy + +``` +rewrite { + regexp .* + to {path} / +} +``` + +#### Firebase のホスティング + +以下を `firebase.json` に追加します: + +``` +{ + "hosting": { + "public": "dist", + "rewrites": [ + { + "source": "**", + "destination": "/index.html" + } + ] + } +} +``` + +## 注意 + +この点に関して注意があります。全ての not-found パスが `index.html` を提供するため、もはや 404 エラーをサーバーがレポートしなくなります。回避策として、Vue アプリケーション内で 404 ページを表示するために catch-all ルートを実装すべきです。 + +``` js +const router = new VueRouter({ + mode: 'history', + routes: [ + { path: '*', component: NotFoundComponent } + ] +}) +``` + +他の方法として、もしあなたが Node.js サーバーを使っている場合、入ってきた URL とマッチさせて、マッチしなかった場合に 404 を返答するサーバーサイドのルーターを使って fallback を実装することもできます。詳細については [Vue サーバサイドレンダリングのドキュメント](https://ssr.vuejs.org/ja/) を参照してください。 diff --git a/docs/ja/guide/essentials/named-routes.md b/docs/ja/guide/essentials/named-routes.md new file mode 100644 index 000000000..24946a609 --- /dev/null +++ b/docs/ja/guide/essentials/named-routes.md @@ -0,0 +1,31 @@ +# 名前付きルート + +しばしば、名前を使ってルートを特定できるとより便利です。特にルートにリンクするときやナビゲーションを実行するときなどです。Router インスタンスを作成するときに `routes` オプションの中でルートに名前を付けることができます。 + +``` js +const router = new VueRouter({ + routes: [ + { + path: '/user/:userId', + name: 'user', + component: User + } + ] +}) +``` + +名前を付けたルートにリンクするには、 `router-link` コンポーネントの `to` プロパティにオブジェクトを渡します。 + +``` html +User +``` + +これはプログラムで `router.push()` を呼び出すときに使われるオブジェクトと全く同じです。 + +``` js +router.push({ name: 'user', params: { userId: 123 }}) +``` + +どちらのケースもルーターは `/user/123` のパスにナビゲーションします。 + +完全な例は [こちら](https://github.com/vuejs/vue-router/blob/dev/examples/named-routes/app.js) です。 diff --git a/docs/ja/guide/essentials/named-views.md b/docs/ja/guide/essentials/named-views.md new file mode 100644 index 000000000..7cc117cab --- /dev/null +++ b/docs/ja/guide/essentials/named-views.md @@ -0,0 +1,86 @@ +# 名前付きビュー + +しばしば、ネストをさせずに同時に複数の view を表示する必要があるでしょう。例えば、`sidebar` view と `main` view を使ったレイアウトを作成する時です。そんな時に名前付きビューは便利です。あなたの view に 1 つのアウトレットを持つのではなく、複数のそれぞれが名前付きの view を持つことができます。名前を持たない `router-view` はその名前として `default` が付与されます。 + +``` html + + + +``` + +1 つの view は 1 つのコンポーネントを使って描画されます。したがって、同じルートに対する複数の view には複数のコンポーネントが必須になります。この `components` (s が付いている) オプションに注意してください。 + +``` js +const router = new VueRouter({ + routes: [ + { + path: '/', + components: { + default: Foo, + a: Bar, + b: Baz + } + } + ] +}) +``` + +この例の動作しているデモは +[こちら](https://jsfiddle.net/posva/6du90epg/) です。 + +## ネストされた名前付きビュー + +ネストされたビューを持つ名前付きビューを使用して複雑なレイアウトを作成することができます。そうする際に、ネストされた `router-view` コンポーネントを使用するために名前をつける必要があります。設定パネルの例を見てみましょう: + +``` +/settings/emails /settings/profile ++-----------------------------------+ +------------------------------+ +| UserSettings | | UserSettings | +| +-----+-------------------------+ | | +-----+--------------------+ | +| | Nav | UserEmailsSubscriptions | | +------------> | | Nav | UserProfile | | +| | +-------------------------+ | | | +--------------------+ | +| | | | | | | | UserProfilePreview | | +| +-----+-------------------------+ | | +-----+--------------------+ | ++-----------------------------------+ +------------------------------+ +``` + +- `Nav` は普通のコンポーネントです +- `UserSettings` はビューコンポーネントです +- `UserEmailsSubscriptions` 、`UserProfile` 、`UserProfilePreview` はネストされたビューコンポーネントです + +**Note**: _そのようなレイアウトに HTML/CSS がどのように表示されるのか、そして使用されるコンポーネントに焦点を当てる方法については、ここでは忘れましょう_ + +上記レイアウトでの `UserSettings` コンポーネントの `