Tabla de contenido Introduction
1.1
Instalación
1.2
Esenciales
1.3
Primeros pasos pasos
1.3.1
Matching dinámico de rutas
1.3.2
Sub-rutas
1.3.3
Navegación media mediante nte código
1.3.4
Rutas con nombre
1.3.5
Vistas con nombre
1.3.6
Redireccionamiento Redireccio namiento y alias
1.3.7
Pasando propiedades a componentes de ruteo
1.3.8
Modo historial historial HTML5
1.3.9
Avanzado
1.4
Guardias de navegación
1.4.1
Campos Meta Meta en las rutas
1.4.2
Transicioness Transicione
1.4.3
Obtención de datos
1.4.4
Comportamiento Comportam iento del scroll
1.4.5
Lazy loading loading
1.4.6
API
1.5 Opciones del constructor de Router
1.5.1
rutas rut as
1.5.1.1
modo
1.5.1.2
base
1.5.1.3
linkActiveClass
1.5.1.4
linkExactActiveClass
1.5.1.5
scrollBehavior
1.5.1.6
parseQuery / stringifyQuery
1.5.1.7
fallback
1.5.1.8
La instancia de Router
1.5.2
Propiedades
1.5.2.1
Métodos
1.5.2.2
El objeto Route
1.5.3
Inyección en componentes
1.5.4
router-link
1.5.5
1
router-view
1.5.6
2
router-view
1.5.6
2
vue-router Notas:
[email protected] [email protected] funciona funciona solamente con Vue 2.x. La documentación para la versión 0.7.x está aquí (en inglés). inglés). Nota Notas s de lanzamiento lanzamiento Instalación Esenciales Primeros pasos pasos Matching dinámico dinámico de de rutas Sub-rutas Navegación mediante mediante código Rutas con nombre nombre Vistas con nombre nombre Redireccionamient Redireccionam iento o y alias Pasando propiedades propiedades a componentes de componentes de ruteo Modo historial historial HTML5 HTML5 Avanzado Guardias de de navegación Campos Meta Meta en las rutas Transicioness Transicione Obtención de datos Comportamiento Comportam iento del scroll Lazy loading loading API Opciones del del constructor de Router Router rutas modo base link ActiveCl ActiveClass ass linkExactAc lin kExactActiveClass tiveClass scr ollBehavior ollBehavior parseQuery / stringifyQuery fallback La instancia de Router Propiedades Métodos El objeto Route Inyección en componentes router-link router-view
3
Instalación Descarga directa / CDN https://unpkg.com/vue-router/dist/vue-router.js Unpkg.com provee enlaces a CDN basadas en NPM. El enlace anterior siempre apuntará a la última versión en Unpkg.com provee NPM. También puedes usar una versión/etiqueta específica a través de URLs como https://unpkg.com/
[email protected]/dist/vue-router.js . Incluye
vue-router
luego de Vue y se instalará automáticamente:
<script src="/ruta/a/vue.js" src="/ruta/a/vue.js"> > <script src="/ruta/a/vue-router.js" src="/ruta/a/vue-router.js"> >
NPM npm install vue-router
Cuando lo utilices con un sistema de empaquetamiento de módulos, debes instalarlo explícitamente a través de Vue.use() : import Vue import Vue from 'vue' import VueRouter import VueRouter from 'vue-router' Vue.use(VueRouter)
No necesitas hacer esto cuando utilices etiquetas script globales. globales.
Versión de desarrollo Debes clonar el repositorio directamente desde GitHub y construir última versión de desarrollo.
vue-router
git clone clone https://github.com/vuejs/vue-router.git https://github.com/vuejs/vue-router.git node_modules/vue-router cd node_modules/vue-router cd node_modules/vue-router npm install npm run build
4
tu mismo si quieres utilizar la
Primeros pasos Utilizaremos ES2015 en el código de los ejemplos en esta guía. Crear una aplicación de una sola página (SPA por sus siglas en inglés) con Vue.js + vue-router es muy sencillo. Con Vue.js, ya estamos estructurando nuestra aplicación con componentes. Cuando agregamos vue-router, todo lo que debemos hacer es mapear nuestros componentes a las rutas e informar a vue-router donde renderizarlas. Aquí hay un ejemplo básico: Todos los ejemplos utilizarán la versión independiente de Vue para hacer posible el análisis de plantillas. Más detalles aquí.
HTML <script src="https://unpkg.com/vue/dist/vue.js"> <script src="https://unpkg.com/vue-router/dist/vue-router.js">
Hello App!
Go to Foo Go to Bar
JavaScript // 0. Si utilizas un sistema de empaquetamiento de módulos (por ejemplo, a través de vue-cli), importa Vue y VueRoute r y luego ejecuta Vue.use(VueRouter). // 1. Define componentes de enrutamiento. // Estos pueden ser importados desde otros archivos const Foo = { template: '
foo
' } const Bar = { template: '
bar
' } // 2. Define algunas rutas // Cada ruta debe mapear a un componente. El "componente" puede // ser un constructor de componente creado a través de // Vue.extend(), o simplemente un objeto de opciones de componente. // Más tarde hablaremos acerca de las sub-rutas. const routes = [ { path: '/foo', component: Foo }, { path: '/bar', component: Bar } ] // 3. Crea una instancia del _router_ y pasa la opción `routes` // Puedes pasar opciones adicionales aquí, // pero mantengámoslo simple por el momento. const router = new VueRouter({ routes // forma corta para routes: routes })
5
// 4. Crea y monta la instancia principal. // Asegúrate de inyectar el _router_ con la opcion router para // garantizar que toda la aplicación tenga acceso al mismo. const app = new Vue({ router }).$mount('#app') // ¡Ahora la aplicación está ejecutándose!
Puedes consultar este ejemplo. Nota que
obtiene automáticamente la clase .router-link-active cuando la ruta a la que apunta es accedida. Puedes leer más acerca de eso en la documentación de la API.
6
Matching dinámico de rutas Es bastante común tener que mapear rutas con un patrón determinado al mismo componente. Por ejemplo, puede que tengamos un componente User el cual debería ser renderizado para todos los usuarios, pero con diferente ID. En vue-router podemos usar un segmento dinámico en el path para lograrlo: const User = { template: 'User
' } const router = new VueRouter({ routes: [ // los segmentos dinámicos comienzan con dos puntos { path: '/user/:id', component: User } ] })
Ahora, las URL como
/user/foo
y
/user/bar
mapearán a la misma ruta.
Un segmento dinámico se representa mediante dos puntos : . Cuando se encuentra una coincidencia en la ruta, el valor del segmento dinámico se expondrá como this.$route.params en cada componente. Por lo tanto, podremos renderizar el ID del usuario actual modificando el template de User de la siguiente manera: const User = { template: 'User {{ $route.params.id }}
' }
Puedes consultar el siguiente ejemplo. Se pueden tener múltiples segmentos dinámicos en la misma ruta, y todos serán mapeados a los correspondientes campos en $route.params . Por ejemplo: patrón
matching de ruta
$route.params
/user/:username
/user/evan
{ username: 'evan' }
/user/:username/post/:post_id
/user/evan/post/123
{ username: 'evan', post_id: 123 }
Además de $route.params , el objeto $route expone más información útil, como $route.query (si hay alguna query en la URL), $route.hash , etc. Puedes verificar todos los detalles en la documentación de la API.
Reaccionando ante cambios de los parámetros Una cosa a tener en cuenta cuando se usan rutas con parámetros es que cuando el usuario navega de /user/foo a /user/bar , la misma instancia del componente será reutilizada. Dado que ambas rutas renderizan el mismo componente, esto es más eficiente que destruir la instancia anterior y crear una nueva. Sin embargo, esto significa que los hooks del ciclo de vida del componentes no serán emitidos. Para detectar cambios en los parámetros en el mismo componente, puedes observar el objeto const User = { template: '...', watch: { '$route' (to, from) {
7
$route
:
// Código que responde al cambio } } }
O utiliza el guardia de navegación
beforeRouteUpdate
introducido en la versión 2.2:
const User = { template: '...', beforeRouteUpdate (to, from, next) { // Código que responde al cambio // no olvides ejecutar next() } }
Patrones de matching avanzados usa path-to-regexp como su motor de búsqueda de patrones, por lo que soporta varios patrones de matching avanzados tales como segmentos dinámicos opcionales, requerimientos del tipo cero o más / uno o más, e incluso patrones regex personalizados. Verifica la documentación para estos patrones avanzados, y este ejemplo de como usarlos con vue-router . vue-router
Prioridad en el matching de patrones A veces la misma URL puede coincidir con múltiples rutas. En ese caso, la prioridad se determina por el orden de la definición de las rutas: la primera ruta definida será la que tenga mayor prioridad.
8
Sub-rutas Las interfaces de usuario (UI por sus siglas en inglés) de aplicaciones reales normalmente están compuestas por componentes que están anidados varios niveles. Es también muy común que los segmentos de una URL correspondan a cierta estructura de componentes anidados, por ejemplo: /user/foo/profile
/user/foo/posts
+------------------+
+-----------------+
| User
| User
|
| +--------------+ | | | Profile
| |
| |
| |
|
| +-------------+ | +------------>
| | Posts
| |
| |
| |
| +--------------+ |
| +-------------+ |
+------------------+
+-----------------+
Con
vue-router
es muy sencillo expresar esta relación usando configuraciones de sub-rutas.
Dada la aplicación que creamos en el capítulo anterior:
const User = { template: 'User {{ $route.params.id }}
' } const router = new VueRouter({ routes: [ { path: '/user/:id', component: User } ] })
Aquí, es un contenedor de nivel superior. Renderiza el componente que coincida con una ruta de nivel superior. Así, un componente renderizado puede contener su propio anidado. Por ejemplo, si agregamos uno dentro de la plantilla del componente User : const User = { template: `
User {{ $route.params.id }}
`
}
Para renderizar componentes dentro de este contenedor anidado, necesitamos usar la opción configuración del constructor de VueRouter : const router = new VueRouter({ routes: [ { path: '/user/:id', component: User, children: [ {
9
children
en la
// UserProfile será renderizado en el dentro de User // cuando /user/:id/profile coincida
path: 'profile', component: UserProfile }, { // UserPosts será renderizado en el dentro de User // cuando /user/:id/posts coincida
path: 'posts', component: UserPosts } ] } ]
})
Nota que las sub-rutas que empiecen con
/
serán tratadas como absolutas. Esto permite aprovechar el
anidamiento de componentes sin tener que usar URL anidadas.
Como puedes ver, la opción children es simplemente otro array de objetos de configuración de rutas, como routes . Por lo tanto, puedes anidar tantas vistas como necesites. En este punto, con la configuración anterior, cuando visites /user/foo , nada será renderizado dentro del contenedor de User porque ninguna sub ruta coincidió. Tal vez quieras renderizar algo ahí. En ese caso, puedes pasar una sub ruta vacía: const router = new VueRouter({ routes: [ {
path: '/user/:id', component: User, children: [ // UserHome será renderizado en el dentro de User // cuando /user/:id coincida { path: '', component: UserHome }, // ...otras sub rutas ] } ]
})
Puedes encontrar una demostración de este ejemplo aquí.
10
Navegación mediante código Además de utilizar para crear etiquetas a para una navegación declarativa, podemos hacer lo mismo a través de código usando los métodos de la instancia del enrutador. router.push(location, onComplete?, onAbort?) Nota: Dentro de una instancia de Vue, tienes acceso a la instancia del router a través de tanto puedes llamar a
this.$router.push
$router
. Por lo
.
Para navegar a una URL diferente, utiliza router.push . Este método agrega una nueva entrada a la pila del historial, por lo que cuando el usuario presione el botón volver del navegador, será llevado a la URL anterior. Este método es el que se llama internamente cuando se hace clic en un componente que es el equivalente a ejecutar router.push(...) . Declarativo
, por lo
Mediante código
router.push(...)
El argumento puede ser una cadena de texto o un objeto descriptor. Por ejemplo: // cadena de texto literal router.push('home') // Objeto router.push({ path: 'home' }) // Ruta con nombre router.push({ name: 'user', params: { userId: 123 }}) // Con _query_, con lo que se obtiene /register?plan=private router.push({ path: 'register', query: { plan: 'private' }})
A partir de la version 2.2.0+, puedes opcionalmente pasar funciones callbacks onComplete y onAbort a router.push o router.replace como segundo y tercer argumento. Estas funciones callbacks serán ejecutadas cuando la navegación sea completada exitosamente (luego que todos los hooks asíncronos sean resueltos), o abortada (navegando a la misma ruta, o a una ruta diferente antes que la navegación actual haya finalizado), respectivamente. router.replace(location, onComplete?, onAbort?)
Actúa como router.push , la única diferencia es que navega sin agregar una nueva entrada al historial, como su nombre sugiere - reemplaza la entrada actual. Declarativo
Mediante código
router.replace(...)
router.go(n)
Este método toma un entero como parámetro que indica cuantos pasos avanzar o retroceder en el historial, similar a window.history.go(n) . 11
Ejemplos // Ir hacia adelante un paso, similar a history.forward() router.go(1) // Ir hacia atrás un paso, similar a history.back() router.go(-1) // Ir 3 pasos hacia adelante router.go(3) // Falla silenciosamente si no existe esa cantidad de registros en el historial router.go(-100) router.go(100)
Manipulación del historial Seguramente notaste que router.push , router.replace y router.go son contra partes de window.history.pushState , window.history.replaceState y window.history.go , y que imitan a las API de window.history . Por lo tanto, si estás familiarizado con las API del historial del navegador , manipularlo será muy sencillo con vuerouter. Vale la pena mencionar que los métodos de navegacion de vue-router ( push , consistentemente en todos los modos de trabajo del router ( history , hash y
12
replace
,
abstract
go
).
) funcionan
Rutas con nombre A veces es conveniente identificar una ruta con un nombre, especialmente cuando enlazamos a esa ruta o navegamos mediante código. Puedes darle un nombre a una ruta en las opciones de routes cuando se crea la instancia de Router: const router = new VueRouter({ routes: [ {
path: '/user/:userId',
name: 'user', component: User } ]
})
Para enlazar a una ruta con nombre, puedes pasar un objeto a la propiedad
to
del componente
User
Este es exactamente el mismo objeto utilizado mediante código con router.push({ name: 'user', params: { userId: 123 }})
En ambos casos, el router navegará a la ruta
/user/123
.
Revisa un ejemplo completo aquí.
13
router.push()
:
router-link
:
Vistas con nombre A veces es necesario mostrar múltiples vistas al mismo tiempo en lugar de anidarlas. Por ejemplo, cuando se crea una plantilla con una vista sidebar y una vista main . Aquí es cuando las vistas con nombre se vuelven útiles. En lugar de tener un solo outlet en tu vista, puedes tener varios y darle a cada uno un nombre diferente. Por defecto, un router-view sin nombre se llamará default .
Una vista se renderiza utilizando un componente, por lo tanto, múltiples vistas requerirán múltiples componentes para la misma ruta. Asegúrate de utilizar la opción components (con una s al final): const router = new VueRouter({ routes: [ {
path: '/', components: { default: Foo, a: Bar, b: Baz } } ]
})
Puedes ver una demostración de este ejemplo aquí.
14
Redireccionamiento y alias Redireccionamiento El redireccionamiento también se realiza en la configuración de /b :
routes
. Para redireccionar desde
/a
hasta
const router = new VueRouter({ routes: [ { path: '/a', redirect: '/b' } ] })
EL redireccionamiento también puede apuntar a una ruta con nombre: const router = new VueRouter({ routes: [ { path: '/a', redirect: { name: 'foo' }} ] })
O incluso puedes utilizar una función para un redireccionamiento dinámico: const router = new VueRouter({ routes: [ { path: '/a', redirect: to => { // la función recibe la ruta destino como argumento // retorna aquí la ruta de redirección. }} ] })
Para otros usos avanzados, tienes el siguiente ejemplo.
Alias Una redirección significa que el usuario visita /a , y la URL será reemplazada por código correspondiente a /b . Pero, ¿qué es un alias? Un alias de
/a
como
/b
significa que cuando el usuario visita
/b
/b
, para luego ejecutar el
, la URL se mantiene como
el código ejecutado corresponderá al mismo que si el usuario visitase
/a
/b
, pero
.
Lo anterior puede ser expresado en la configuración de enrutamiento como: const router = new VueRouter({ routes: [ { path: '/a', component: A, alias: '/b' } ] })
Un alias te da la libertad de mapear una estructura de UI a una URL arbitraria, en lugar de estar restringido por la estructura anidada de la configuración.
15
Para otros usos avanzados, aquí tienes un ejemplo.
16
Pasando propiedades a componentes de ruteo Usar $route en tu componente genera un acoplamiento estrecho con la ruta, lo cual limita la flexibilidad del componente dado que solo puede utilizarse en ciertas URL. Para desacoplar el componente del enrutador utiliza props: Acoplado a $route const User = { template: 'User {{ $route.params.id }}
' } const router = new VueRouter({ routes: [ { path: '/user/:id', component: User } ] })
Desacoplado con props const User = { props: ['id'], template: 'User {{ id }}
' } const router = new VueRouter({ routes: [ { path: '/user/:id', component: User, props: true }, // utilizando vistas con nombre, tienes que definir la opción prop para cada una de ellas: {
path: '/user/:id', components: { default: User, sidebar: Sidebar }, props: { default: true, sidebar: false } } ]
})
Esto te permite utilizar el componente en cualquier lugar, lo cual hace al mismo reutilizable y más sencillo de testear.
Modo boolean Cuando props tiene asignado el valor true,
route.params
serán asignados como las props del componente.
Modo objeto Cuando props es un objeto, este será asignado tal cual como las props del componente. Úitl para cuando las props son estáticas. const router = new VueRouter({ routes: [ { path: '/promotion/from-newsletter', component: Promotion, props: { newsletterPopup: false } } ] })
17
Modo función Puedes crear una función que retorne props. Esto te permite convertir los parámetros a otro tipo, combinar valores estáticos con valores basados en rutas, etc. const router = new VueRouter({ routes: [ { path: '/search', component: SearchUser, props: (route) => ({ query: route.query.q }) } ] })
La URL:
/search?q=vue
pasaría
{query: "vue"}
como props al componente SearchUser.
Intenta crear funciones props sin estado, dado que solo se evalúan cuando ocurren cambios de ruta. Utiliza un componente envolvente si necesitas estado para definir las props, de esa manera Vue puede reaccionar a cambios de estado. Para un uso avanzado, aquí hay un ejemplo.
18
Modo historia HTML5 El modo por defecto para vue-router es hash mode - el cual utiliza una almohadilla para simular la URL completa para que la página no sea recargada cuando la URL cambia. Para eliminar la almohadilla, podemos seleccionar el modo historia del router , el cual utiliza el método history.pushState de la API para conseguir una navegación sin recarga de página: const router = new VueRouter({ mode: 'history', routes: [...] })
Cuando utilices el modo historial, la URL lucirá "normal", por ejemplo:
http://oursite.com/user/id .
¡Hermoso!
Sin embargo, hay un problema: dado que nuestra aplicación es de una sola página del lado cliente, sin una configuración apropiada del lado servidor los usuarios van a obtener errores 404 si intentan acceder directamente a http://oursite.com/user/id en sus navegadores. Eso es horrible. No hay problema: para solucionar el error, todo lo que debes hacer es agregar un redireccionamiento en tu servidor. Si la URL no coincide con ningún recurso estático, debes apuntar a la misma página index.html donde se encuentra tu aplicación. De nuevo, ¡Hermoso!
Ejemplos de configuraciones de servidores Apache RewriteEngine On RewriteBase / RewriteRule ^index\.html$ - [L] RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule . /index.html [L]
nginx location / { try_files $uri $uri/ /index.html; }
Node.js (Express) Para Node.js/Express, considera utilizar el middleware connect-history-api-fallback.
Deventajas 19
Hay una deventaja para esto: tu servidor ya no reportará errores 404 dado que todas las rutas no encontradas serán redireccionadas al archivo index.html . Para solucionar este problema debes implementar dentro de la aplicación Vue una ruta por defecto para mostrar una página de error 404: const router = new VueRouter({ mode: 'history', routes: [ { path: '*', component: NotFoundComponent } ] })
Otra solución, si utilizas un servidor Node.js, es utilizar el router del lado del servidor para analizar las URL ingresadas y responder con un error 404 si ninguna ruta coincide.
20
Guardias de navegación Como el nombre sugiere, las guardias de navegación provistas por vue-router son básicamente utilizadas para proteger rutas de navegación ya sea redireccionando o cancelándolas. Hay varias maneras de engancharse en el proceso de navegación de rutas: globalmente, por ruta o dentro de los componentes. Recuerda: Los cambios en los parámetros o las queries no harán que se ejecuten los guardias de navegación. Simplemente observa el objeto $route para poder reaccionar frente a esos cambios o utiliza el guardia beforeRouteUpdate en el componente.
Guardias globales Puedes registrar guardias before globales utilizando
router.beforeEach
:
const router = new VueRouter({ ... }) router.beforeEach((to, from, next) => { // ... })
Las guardias before globales son llamadas por orden de creación, cuando una navegación comienza. Las guardias pueden ejecutarse asincrónicamente, y la navegación se considera pendiente hasta que todos los hooks sean resueltos. Cada función guardia recibe tres argumentos: to: Route
: el Objeto Route hacia donde se navega.
from: Route
: la ruta actual desde la cual se navega.
: esta función debe ser ejecutada para resolver el hook . La acción a realizar depende de los argumentos provistos a next : next: Function
next()
: moverse al siguiente hook en la cadena. Si no queda ninguno, la navegación se confirma.
: cancelar la navegación actual. Si la URL en el navegador cambió (ya sea manualmente o a través del botón atrás), será reseteada al valor de la ruta from . next(false)
next('/')
o
next({ path: '/' })
: redirecciona a una ruta diferente. La navegación actual será abortada
y una nueva será iniciada. : (2.4.0+) si el argumento pasado a next es una instancia de Error , la navegación se abortará y el error será pasado a las funciones callback registradas a través de router.onError() . next(error)
Asegúrese de llamar siempre a la función
next
, sino el hook nunca será resuelto.
Guardias de resolución globales Nuevo en 2.5.0 A partir de la versión 2.5.0 puedes registrar un guardia global con router.beforeResolve . Esto es similar a router.beforeEach , con la diferencia que los guardias de resolución serán llamados justo antes de que la navegación sea confirmada, después que todos los guardias en el componente y los componentes de 21
rutas asíncronos sean resueltos.
Post hooks globales También puedes registrar hooks globales que se ejecutarán después de que la navegación sea confirmada. Sin embargo, a diferencia de los guardias, estos hooks no reciben una función next y no pueden afectar la navegación: router.afterEach((to, from) => { // ... })
Guardias por ruta Puedes definir guardias
beforeEnter
directamente en el objeto de configuración de una ruta:
const router = new VueRouter({ routes: [ {
path: '/foo', component: Foo, beforeEnter: (to, from, next) => { // ... } } ]
})
Estos guardias tienen exactamente la misma firma que los guardias before globales.
Guardias en componentes Por último, puedes directamente definir guardias de navegación dentro de los componentes de ruta (los que son pasados a la configuración del router ) con las siguientes opciones: beforeRouteEnter beforeRouteUpdate
(agregado en la versión 2.2)
beforeRouteLeave
const Foo = { template: `...`, beforeRouteEnter (to, from, next) { // se llama antes que la ruta que renderiza este componente sea confirmada. // NO tiene acceso a la instancia del componente `this`, // ¡porque no ha sido creada todavía cuando este guardia es ejecutado! }, beforeRouteUpdate (to, from, next) { // se llama cuando la ruta que renderiza este componente ha cambiado, // pero este componente es reusado en la nueva ruta. // Por ejemplo, para una ruta con parámetros dinámicos /foo/:id, cuando // navegamos desde /foo/1 havia /foo/2, la misma instancia del componente Foo // será reusada, y este _hook_ será llamado cuando eso suceda. // Tiene acceso a la instancia del componente `this` }, beforeRouteLeave (to, from, next) { // se llama cuando la ruta que renderiza el componente está por ser // abandonada.
22
// Tiene acceso a la instancia del componente `this` } }
La guardia beforeRouteEnter NO tiene acceso a this , porque es ejecutada antes que la navegación sea confirmada, por lo tanto el componente destino todavía no ha sido creado. Sin embargo, puedes acceder a la instancia pasando una función callback a next . La función callback se ejecutará cuando la navegación sea confirmada, y la instancia del componente será pasada como argumento: beforeRouteEnter (to, from, next) { next(vm => { // accede a la instancia del componente a través de `vm` }) }
Puedes acceder directamente a this dentro de beforeRouteLeave . La guardia leave se utiliza normalmente para prevenir al usuario cuando intenta abandonar la ruta accidentalmente sin guardar cambios. La navegación puede ser cancelada ejecutando next(false) .
El flujo de resolución de navegación completo 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12.
Se dispara la navegación. Se llaman a los guardias leave en los componentes desactivados. Se llaman a los guardias beforeEach globales. Se llaman a los guardias beforeRouteUpdate en los componentes reutilizados (2.2+). Se llama a beforeEnter en las configuraciones de rutas. Se resuelven componentes de rutas asíncronos. Se llama a beforeRouteEnter en los componentes activados. Se llama a los guardias globales beforeResolve (2.5+). Se confirma la navegación. Se llaman a los hook globales afterEach . Se disparan las actualizaciones del DOM. Se llaman a las funciones callback pasadas a next en los guardias beforeRouteEnter con las instancias creadas.
23
Campos Meta en las rutas Puedes incluir un campo
meta
cuando definas una ruta:
const router = new VueRouter({ routes: [ {
path: '/foo', component: Foo, children: [ {
path: 'bar', component: Bar, // campo meta meta: { requiresAuth: true } } ] } ]
})
Entonces, ¿como accedemos al campo
meta
?
Primero, cada objeto route en la configuración de routes se llama registro de ruta. Los registros de ruta pueden estar anidados. Por lo tanto, cuando una ruta coincida, existe la posibilidad que lo haga con más de un registro de ruta. Por ejemplo, con la configuración anterior, la URL con el hijo.
/foo/bar
coincidirá tanto con el registro de ruta padre como
Todos los registros de rutas que hayan coincidido son expuestos en el objeto $route (y también a los objetos route en las guardias de navegación) como el array $route.matched . Por ende, necesitaremos iterar sobre $route.matched para verificar campos meta en los registros de rutas. Un caso de uso de ejemplo es verificar la existencia de campos metas en los guardias de navegación global: router.beforeEach((to, from, next) => { if (to.matched.some(record => record.meta.requiresAuth)) { // esta ruta requiere autenticación, verificamos que haya iniciado sesión // sino, redirigimos a la página de inicio de sesión. if (!auth.loggedIn()) {
next({
path: '/login', query: { redirect: to.fullPath } }) } else {
next() } } else {
next() // ¡Asegúrate de ejecutar next siempre! }
})
24
25
Transiciones Dado que es esencialmente un componente dinámico, podemos aplicarle efectos de transición utilizando el componente :
Todo acerca de
también funciona aquí.
Transiciones por ruta El ejemplo anterior aplicará la misma transición a todas las rutas. Si deseas que cada componente de ruta tenga diferentes transiciones, puedes utilizar con diferentes nombres dentro de cada componente de ruta: const Foo = { template: ` ...
`
} const Bar = { template: ` ...
`
}
Transiciones dinámicas basadas en componentes También es posible determinar dinámicamente la transición a utilizar basado en las relaciones entre la ruta destino y la ruta actual:
// luego, en el componente padre, // observa $route para determinar que transición utilizar watch: { '$route' (to, from) { const toDepth = to.path.split('/').length const fromDepth = from.path.split('/').length this.transitionName = toDepth < fromDepth ? 'slide-right' : 'slide-left' } }
Tienes un ejemplo completo aquí. 26
27
Obtención de datos A veces es necesario obtener datos del servidor cuando una ruta es activada. Por ejemplo, antes de renderizar un perfil de usuario, puedes obtener la información de ese usuario desde el servidor. Podemos lograr esto de dos maneras diferentes: Obtener la información después de la navegación: realiza la navegación primero y luego obtén los datos
en un hook del ciclo de vida del componente entrante. Puedes mostrar un indicador de carga mientras se obtienen los datos. Obtener la información antes de la navegación: Obtén los datos antes de la navegación en la guardia de
entrada de la ruta, y realiza la navegación una vez estos obtenidos. Técnicamente, ambas opciones son válidas - todo depende de la experiencia de usuario a la que apuntes.
Obtener la información después de la navegación Cuando utilizamos este enfoque, navegamos y renderizamos el componente entrante inmediatamente, y obtenemos los datos en el hook created del componente. Esto nos permite mostrar un indicador de estado de carga mientras se obtiene la información desde un servidor remoto, y también manejar la carga de datos según la ruta. Asumamos que tenemos un componente $route.params.id :
Post
que necesita obtener datos de un post basándose en
Loading...
{{ error }}
{{ post.title }}
{{ post.body }}
export default { data () { return {
loading: false,
post: null,
error: null } }, created () { // obtén los datos cuando la vista es creada y _data_ ya // está siendo observada this.fetchData() },
28
watch: { // ejecuta nuevamente el método si la ruta cambia '$route': 'fetchData' }, methods: { fetchData () { this.error = this.post = null this.loading = true // reemplaza getPost con lo que corresponda
getPost(this.$route.params.id, (err, post) => { this.loading = false if (err) { this.error = err.toString() } else { this.post = post } }) } }
}
Obtener la información antes de la navegación Con este enfoque, obtenemos la información antes de navegar a la nueva ruta. Podemos obtener los datos en el guardia beforeRouteEnter del componente entrante, y solo ejecutar next cuando se haya completado: export default { data () { return {
post: null,
error: null } }, beforeRouteEnter (to, from, next) { getPost(to.params.id, (err, post) => { next(vm => vm.setData(err, post)) }) }, // cuando la ruta cambie y este componente ya haya sido renderizado, // la lógica será ligeramente diferente 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 } } }
}
29
El usuario permanecerá en la vista anterior mientras se esté obteniendo el recurso para la vista entrante. Por lo tanto, es recomendable mostrar algún tipo de indicador o barra de progreso. Si la obtención de datos falla, es necesario mostrar algún tipo de advertencia global.
30
Comportamiento del scroll Cuando se utiliza enrutamiento del lado cliente, podemos querer hacer scroll hacia el inicio de la página cuando naveguemos a una nueva ruta, o preservar la posición actual, tal cual lo hace una recarga de la página. vue-router te permite lograr esto e incluso más: permite personalizar completamente el comportamiento del scroll durante la navegación. Nota: esta característica solo funciona en el modo historial de HTML5.
Cuando crees una instancia del
router
, puedes incluir la función
scrollBehavior
:
const router = new VueRouter({ routes: [...], scrollBehavior (to, from, savedPosition) { // devolver la posición deseada } })
La función scrollBehavior recibe los objetos de ruta to y from . El tercer parámetro, savedPosition , solo está disponible si estamos en una navegación popstate (cuando se utilizan los botones atrás o adelante en el navegador). La función puede devolver un objeto de posición de
scroll
. El objeto puede ser de la forma:
{ x: number, y: number } { selector: string, offset? : { x: number, y: number }}
(offset solo soportado a partir de la versión 2.6.0+)
Si se devuelve un valor falso o un objeto vacio, no ocurrirá ningún desplazamiento. Por ejemplo: scrollBehavior (to, from, savedPosition) { return { x: 0, y: 0 } }
Esto hará que la página se desplace hacia el inicio para todas las navegaciones a la ruta. Devolver nativo:
savedPosition
hará que el comportamiento cuando se utilicen los botones atrás o adelante sea el
scrollBehavior (to, from, savedPosition) { if (savedPosition) { return savedPosition } else { return { x: 0, y: 0 } } }
Si deseas simular el
scroll
hacia anclas:
scrollBehavior (to, from, savedPosition) { if (to.hash) { return { selector: to.hash
31
// , offset: { x: 0, y: 10 } } } }
También podemos utilizar campos meta para implementar un control de
32
scroll
fino. Un ejemplo completo aquí.
Lazy loading Cuando se construyen aplicaciones con un sistema de empaquetamiento de módulos, el archivo JavaScript resultante puede terminar siendo muy grande, afectando los tiempos de carga de la página. Sería más eficiente si pudiesemos dividir los componentes de cada ruta en porciones separadas y cargarlas solo cuando esa ruta es visitada. Combinando las características asíncronas de componentes de Vue y las características de división de código de Webpack, es trivial el lazy loading de componentes de ruta. Todo lo que necesitamos es definir nuestros componentes de rutas como asíncronos: const Foo = resolve => { // require.ensure es la sintaxis especial de Webpack para indicar un punto de división de código. require.ensure(['./Foo.vue'], () => {
resolve(require('./Foo.vue')) })
}
Hay una alternativa a la sintaxis de división de código utilizando require como lo hace AMD, por lo que puede simplificarse como: const Foo = resolve => require(['./Foo.vue'], resolve)
Nada debe cambiarse en la configuración del router , solo utiliza
Foo
como lo harías normalmente:
const router = new VueRouter({ routes: [ { path: '/foo', component: Foo } ] })
Agrupando componentes en la misma porción A veces deseamos agrupar todos los componentes bajo la misma ruta en la misma porción asíncrona. Para lograr esto, necesitamos usar porciones con nombre proveyendo un nombre de porción a require.ensure como el tercer argumento: const Foo = r => require.ensure([], () => r(require('./Foo.vue')), 'group-foo') const Bar = r => require.ensure([], () => r(require('./Bar.vue')), 'group-foo') const Baz = r => require.ensure([], () => r(require('./Baz.vue')), 'group-foo')
Webpack agrupará los módulos asíncronos con el mismo nombre dentro de la misma porción asíncrona - esto también significa que no necesitamos más listar explícitamente las dependencias de require.ensure (por lo tanto pasamos un array vacío).
33
34
Opciones del constructor de Router routes tipo:
Array
Declaración de tipos para
RouteConfig
:
declare type RouteConfig = { path: string; component?: Component; name?: string; // para rutas con nombre components?: { [name: string]: Component };// para vistas con nombre redirect?: string | Location | Function; props?: boolean | string | Function; alias?: string | Array; children?: Array; // para sub-rutas beforeEnter?: (to: Route, from: Route, next: Function) => void; meta?: any; // 2.6.0+ caseSensitive?: boolean; // utilizar o no matcheo case sensitive (valor por defecto: false) pathToRegexpOptions?: Object; // Opciones path-to-regexp para compilar expresiones regulares }
mode tipo:
string
valor por defecto:
"hash" (en navegadores) | "abstract" (en Node.js)
valores disponibles:
"hash" | "history" | "abstract"
Configura el modo del
router
.
: utiliza el hash en la URL para el enrutamiento. Funciona en todos los navegadores que soportan Vue, incluidos aquellos que no soportan la API de historial de HTML5 . hash
history
: requiere la API de historial de HTML y configuración del lado servidor. Modo historial HTML5.
abstract
: funciona en todos los ambientes de JavaScript, por ejemplo, del lado servidor con Node.js.
Se forzará este modo de trabajo en el router si no se detecta la API de navegador.
base tipo:
string
valor por defecto:
"/"
La URL base para la aplicación. Por ejemplo, si toda la aplicación se encuentra dentro de base debería llevar ese valor.
linkActiveClass tipo:
string
35
/app/
, entonces
valor por defecto:
"router-link-active"
Configura globalmente la clase activa por defecto de
. Más información en router-link.
linkExactActiveClass 2.5.0+ tipo:
string
valor por defecto:
"router-link-exact-active"
Configura globalmente la clase activa de información en router-link.
para coincidencias de rutas exactas. Más
scrollBehavior tipo:
Function
Firma: ( to: Route, from: Route, savedPosition?: { x: number, y: number } ) => { x: number, y: number } | { selector: string } | ?{}
Para más detalles, comportamiento del scroll.
parseQuery / stringifyQuery 2.4.0+ tipo:
Function
Provee funciones parse / stringify para query string personalizadas. Sobreescribe la función por defecto.
fallback 2.6.0+ tipo:
boolean
Controla si el router debe o no utilizar el modo valor por defecto es true .
hash
cuando el navegador no soporte
history.pushState
. El
Configurar esto como false hace que cada navegación a través de router-link sea una recarga completa de la página en IE9. Esto es útil cuando la aplicación es renderizada en el servidor y necesita funcionar en IE9, porque las URL en modo hash no funcionan con SSR.
36
La instancia de Router Propiedades router.app tipo:
Vue instance
La instancia principal de Vue donde
router
fue inyectado.
router.mode tipo:
string
El modo que
router
está utilizando.
router.currentRoute tipo:
Route
La ruta actual representada como un objeto Route.
Métodos router.beforeEach(guard) router.beforeResolve(guard) (2.5.0+) router.afterEach(hook)
Agrega guardias de navegación globales. Info: guardias de navegación. A partir de la versión 2.5.0 los tres métodos devuelven una función que elimina el guardia/hook registrado. router.push(location, onComplete?, onAbort?) router.replace(location, onComplete?, onAbort?) router.go(n) router.back() router.forward()
Navega mediante código a una nueva URL. Info: navegación mediante código. router.getMatchedComponents(location?)
Devuelve un array de componentes (definiciones/constructores, no instancias) que coincidan con la ubicación provista o la ruta actual. Se utiliza principalmente durante el renderizado del lado servidor para realizar precarga de datos. router.resolve(location, current?, append?)
2.1.0+ Resolución inversa de URL. Dada una ubicación de la misma forma que las usadas en devuelve un objeto con las siguiente propiedades: 37
,
{ location: Location; route: Route; href: string; }
router.addRoutes(routes)
2.2.0+ Agrega dinámicamente más rutas al router . El argumento debe ser un array utilizando el mismo formato de configuración que las opciones del constructor de routes . router.onReady(callback, [errorCallback])
2.2.0+ Este método pone una función callback en espera a ser llamada cuando el router haya completado la navegación inicial, lo cual significa que ya ha resuelto todos los hooks de entrada asíncronos y los componentes asíncronos asociados con la ruta inicial. Esto es útil en el renderizado del lado servidor para asegurar un resultado consistente tanto en el servidor como en el cliente. El segundo argumento, errorCallback , solo es soportado a partir de la versión 2.4. Será llamado cuando la resolución de ruta inicial devuelva un error (por ejemplo, cuando falla la resolución de un componente asíncrono). router.onError(callback)
2.4.0+ Registra una función callback la cual será llamada cuando un error es capturado durante la navegación. Ten en cuenta que sucederá solo en las siguientes situaciones: El error es lanzado sincrónicamente dentro de una función de guardia de ruta; El error es capturado y manejado asíncronamente llamando a guardia de ruta;
next(err)
dentro de una función de
El error ocurre cuando se intenta resolver un componente asíncrono que es necesario para renderizar una ruta.
38
El objeto Route Un objeto Route representa el estado de la ruta activa actualmente. Contiene información analizada de la URL actual y los registros de rutas que coinciden con ella. El objeto
Route
es inmutable. Cada navegación exitosa resultará en un nuevo objeto
El objeto
Route
puede encontrarse en diferentes lugares.
Dentro de los componentes, como
Route
.
this.$route
Dentro de las funciones callbacks de observación de Como valor de retorno de la función
$route
router.match(location)
Dentro de las guardias de navegación como los primeros dos argumentos: router.beforeEach((to, from, next) => { // to y from son objetos de ruta })
Dentro de la función
scrollBehavior
como los primeros dos argumentos:
const router = new VueRouter({ scrollBehavior (to, from, savedPosition) { // to y from son objetos de ruta } })
Propiedades del objeto Route $route.path
tipo:
string
Una cadena de texto equivalente a la ruta actual, siempre resuelta como una ruta absoluta. Por ejemplo "/foo/bar" . $route.params
tipo:
Object
Un objeto que contiene pares llave/valor de segmentos dinámicos y segmentos estrella. Si no hay parametros, el valor será un objeto vacio. $route.query
tipo:
Object
Un objeto que contiene pares llave/valor del query string . Por ejemplo, para la ruta /foo?user=1 , obtendremos $route.query.user == 1 . Si no hay query string el valor será un objeto vacio. $route.hash
tipo:
string
39
El hash de la ruta actual (con la vacia.
#
), si posee. Si no hay un hash el valor será una cadena de texto
$route.fullPath
tipo:
string
La URL completa incluyendo query y hash. $route.matched
tipo: Array Un array que contiene registros de ruta para todos los segmentos anidados de la ruta actual. Los registros de ruta son copias de los objetos en el array de configuración routes (y en los arrays children ): const router = new VueRouter({ routes: [ // el siguiente objeto es un registro de ruta { path: '/foo', component: Foo, children: [ // este también es un registro de ruta { path: 'bar', component: Bar } ] } ] })
Cuando la URL es /foo/bar , $route.matched será un array que contendrá ambos objetos (clonados), en orden descendente de padre a hijo. $route.name
El nombre de la ruta acutal, si tiene. (Más información en rutas con nombre)
40
Inyección en componentes Propiedades inyectadas Estas propiedades son inyectadas dentro de cada componente hijo pasando la instancia del instancia principal como la opción router .
router
a la
$router La instancia del
router
.
$route El objeto Route activo. Esta propiedad es de solo lectura y sus propiedades son inmutables, pero puede ser observada.
Opciones habilitadas beforeRouteEnter beforeRouteUpdate (agregado en 2.2) beforeRouteLeave
Más información en guardias en componentes.
41
es el componente para posibilitar la navegación de los usuarios en una aplicación con el router habilitado. La ubicación destino se especifica con la propiedad to . Por defecto, renderiza una etiqueta con el atributo href correspondiente, pero puede configurarse mediante la propiedad tag . Además, el enlace obtiene una clase CSS cuando la ruta a la que apunta es activada.
Es preferible utilizar
en lugar de escribir directamente
por las siguientes razones:
Funciona de la misma manera tanto en el modo hash como en el modo historial de HTML5, por lo que si decides intercambiar modos, o cuando el router utiliza el modo hash en IE9, no deberás modificar nada. En el modo historial de HTML5, recargar la página.
router-link
Cuando estés utilizando la opción la propiedad to .
base
interceptará el evento click para que el navegador no intente
en el modo historial de HTML5, no necesitas incluirla en la URL de
Propiedades to
tipo:
string | Location
requerida Identifica la ruta destino del enlace. Cuando es accedida, el valor de la propiedad to será pasado a router.push() internamente, por lo que el valor puede ser tanto una cadena de texto como un objeto descriptor de ubicación. Home Home Home Home Home User Register
replace
tipo:
boolean
valor por defecto:
false
42
Establecer la propiedad replace ejecutará router.replace() en lugar de por lo que la navegación no dejará un registro en el historial.
router.push()
cuando se acceda,
append
tipo:
boolean
valor por defecto:
false
Establecer la propiedad append hará que se agregue la ruta relativa a la ruta actual. Por ejemplo, asumiendo que estamos navegando desde /a a un enlace relativo b , sin append accederemos a pero con append accederemos a /a/b .
/b
,
tag
tipo:
string
valor por defecto:
"a"
A veces puede que quieras que se renderice como otra etiqueta, por ejemplo . Puedes utilizar la propiedad tag para especificar que etiqueta renderizar, y seguirá escuchando eventos click para la navegación. foo foo
active-class
tipo:
string
valor por defecto:
"router-link-active"
Configura la clase CSS que se aplicará al enlace cuando este activo. Nota que el valor por defecto puede ser configurado de manera global a través de la opción linkActiveClass del constructor del router . exact
tipo:
boolean
valor por defecto:
false
El comportamiento por defecto para la aplicación de la clase CSS activa en matching dinámico de rutas es inclusivo. Por ejemplo, obtendrá la clase CSS mientras la ruta actual comience con /a/ o sea /a . Una consecuencia de esto es que ¡permanecerá activa para todas las rutas! Para forzar un matching exacto, utiliza la propiedad exact :
43
Más ejemplos explicando la clase activa aquí. event
2.1.0+ tipo:
string | Array
valor por defecto:
'click'
Son los eventos que permiten lanzar la navegacion. exact-active-class
2.5.0+ tipo:
string
valor por defecto:
"router-link-exact-active"
Configura la clase CSS activa que será aplicada cuando el enlace esté activo con una coincidencia de ruta exacta. Ten en cuenta que el valor por defecto también puede configurarse globalmente a través de la opción linkExactActiveClass del constructor del router.
Aplicar la clase activa al elemento envolvente. A veces puede que queramos que la clase activa se aplique al elemento envolvente en lugar de aplicarla directamente a la etiqueta . En ese caso, puedes renderizar el elemento envolvente utilizando y luego una etiqueta dentro: /foo
En este caso, la etiqueta será el enlace (y obtendrá el atributo aplicada al elemento envolvente .
44
href
correcto), pero la clase activa será