在一个页面中,须要根据路由得到参数,而后在页面进行逻辑处理,能够经过$route来获取相关参数前端
可是这样一来,页面组件与路由耦合过高,为了解耦,页面组件能够在更大程度上进行复用,可使用路由组组传参vue
路由组件传参有三种形式web
适用于在动态路由匹配中,有动态路由参数的路由配置中vue-router
在前面的例子里,定义了一个动态路由参数的路由后端
修改src/router/router/js
文件浏览器
import Home from '@/views/Home.vue' export default [ { path: '/', name: 'home', alias:'/home_page', component: Home, }, { path: '/about', name: 'about', component: () => import('@/views/About.vue'), },{ path:'/argu/:name', name:'argu', component:() => import('@/views/argu.vue'), props:true } ]
修改src/views/argu.vue
文件内容为:app
<template> <div> {{ $route.params.name }} </div> </template> <script> export default { } </script>
用浏览器打开URL:http://localhost:8080/#/argu/orange
,效果以下less
在上面的argu页面,能够经过$route对象
获取动态路由中的参数,此时也可使用布尔模式获取动态路由中定义的参数异步
修改src/router/router/js
文件,定义布尔模式来获取动态路由参数函数
import Home from '@/views/Home.vue' export default [ { path: '/', name: 'home', alias:'/home_page', component: Home, }, { path: '/about', name: 'about', component: () => import('@/views/About.vue'), },{ path:'/argu/:name', name:'argu', component:() => import('@/views/argu.vue'), props:true // 定义布尔模式获取路由参数 } ]
修改src/views/argu.vue
文件
<template> <div> {{ name }} </div> </template> <script> export default { props:{ name:{ type:String, // 定义name的值的类型,String表示name的值必须为字符串,Number表示name的值为整数 default:'renpingsheng' // 定义默认值,能够省略 } } } </script>
更改路由的参数,效果以下
普通路由的传值,例如在about路由页面中传参
修改src/router/router.js
文件,在about路由中传值
import Home from '@/views/Home.vue' export default [ { path: '/', name: 'home', alias:'/home_page', component: Home, }, { path: '/about', name: 'about', component: () => import('@/views/About.vue'), props:{ fruit:"banana" } },{ path:'/argu/:name', name:'argu', component:() => import('@/views/argu.vue'), props:true } ]
而后修改src/views/About.vue
文件
<template> <div class="about"> <h1>This is an about page</h1> <b>{{ fruit }}</b> </div> </template> <script> export default { props:{ fruit:{ type:String, default:'apple' // 默认值,若是路由中没的传递任何值则在页面上显示默认值 } } } </script>
因为/about路由中传递了fruit的值,因此页面显示效果以下
此时若是在路由的props属性中没有传递fruit的值
import Home from '@/views/Home.vue' export default [ { path: '/', name: 'home', alias:'/home_page', component: Home, }, { path: '/about', name: 'about', component: () => import('@/views/About.vue'), props:{ // fruit:"banana" // 把传递参数的这一行注释 } },{ path:'/argu/:name', name:'argu', component:() => import('@/views/argu.vue'), props:true } ]
src/views/About.vue文件内容不变,则页面上就会显示About.vue文件中props属性中定义的默认值,显示效果以下
适合在传入的属性中可以根据当前的路由进行逻辑判断,从而设置传入组件的属性值
修改src/router/router/js
文件,修改home路由
import Home from '@/views/Home.vue' export default [ { path: '/', name: 'home', alias:'/home_page', component: Home, props: route => ({ fruit: route.query.params }) }, { path: '/about', name: 'about', component: () => import('@/views/About.vue'), props:{ // fruit:"banana" } },{ path:'/argu/:name', name:'argu', component:() => import('@/views/argu.vue'), props:true } ]
修改src/views/Home.vue
文件
<template> <div class="home"> <b>{{ fruit }}</b> <br> <button @click="handleClick">返回上一页</button> </div> </template> <script> export default { name: 'home', props:{ fruit:{ type: String, default:'strawberry' } }, methods:{ handleClick () { this.$router.push({ name:`argu`, params:{ name:'banana' } }) } } } </script>
此时用浏览器打开URL: http://localhost:8080/#/?params=orange
,显示效果以下
删除URL中添加的params键值对,页面显示效果以下
当URL中包含params键值对时,页面上就会显示URL中params的值
当URL中没有传入params键值对时,页面上就会显示props中定义的默认值
导航守卫在实际开发中都会用到的技能,大体至关于后端开发中的中间件功能
可以在路由发生跳转到导航结束这个阶段内进行一些相应的逻辑处理
好比用户打开某个须要登陆的页面时判断用户是否登陆,若是用户已经登陆则直接打开页面
若是用户没有登陆就跳转到登陆页面
再好比用户在一个页面编辑了内容,当用户跳转到别的页面时提醒用户是否保存等功能均可以由导航守卫来完成
全局守卫就是在全局设置的守卫
修改src/router/index.js
文件,添加全局守卫
import Vue from 'vue' import Router from 'vue-router' import routes from './router' Vue.use(Router) const router = new Router({ routes }) const IS_LOGINED = true // 模拟用户是否登陆 router.beforeEach((to,from,next) => { if(to.name !== 'login'){ if(IS_LOGINED) next() else next({name:'login'}) }else{ if(IS_LOGINED) next({name:'home'}) else next() } }) export default router
修改src/router/router.js
文件,添加login命名路由
import Home from '@/views/Home.vue' export default [ { path: '/', name: 'home', alias:'/home_page', component: Home, props: route => ({ fruit: route.query.params }) }, { path: '/about', name: 'about', component: () => import('@/views/About.vue'), props:{ // fruit:"banana" } },{ path:'/argu/:name', name:'argu', component:() => import('@/views/argu.vue'), props:true },{ path:'/login', name:'login', component:() => import('@/views/login.vue') } ]
而后在src/views/目录下新建login.vue文件
,文件内容以下
<template> <div> <b>this is login page</b> </div> </template> <script> export default { } </script>
在浏览器中输入路由列表中已配置的任何URL,都会进入对应的页面
当把src/router/index.js
文件中IS_LOGINED的值设置为false
时
import Vue from 'vue' import Router from 'vue-router' import routes from './router' Vue.use(Router) const router = new Router({ routes }) const IS_LOGINED = false router.beforeEach((to,from,next) => { if (to.name !== 'login') { if (IS_LOGINED) next() else next({ name: 'login' }) } else { if (IS_LOGINED) next({ name: 'home' }) else next() } }) export default router
在浏览器中输入任何URL,都会进入login页面
每一个守卫方法接收三个参数:
to: Route: 即将要进入的目标 路由对象 from: Route: 当前导航正要离开的路由 next: Function: 必定要调用该方法来 resolve 这个钩子。执行效果依赖 next 方法的调用参数。 其中,next方法能够传入的参数: next(): 进行管道中的下一个钩子。若是所有钩子执行完了,则导航的状态就是 confirmed (确认的)。 next(false): 中断当前的导航。若是浏览器的 URL 改变了 (多是用户手动或者浏览器后退按钮),那么 URL 地址会重置到 from 路由对应的地址。 next('/') 或者 next({ path: '/' }): 跳转到一个不一样的地址。当前的导航被中断,而后进行一个新的导航。你能够向 next 传递任意位置对象,且容许设置诸如 replace: true、name: 'home' 之类的选项以及任何用在 router-link 的 to prop 或 router.push 中的选项。
必定要确保在全部路由守卫最后要执行next方法,不然钩子就不会被 resolved
后置守卫不能阻止页面的跳转
修改src/router/index.js
文件,设置后置守卫
import Vue from 'vue' import Router from 'vue-router' import routes from './router' Vue.use(Router) const router = new Router({ routes }) const IS_LOGINED = true router.beforeEach((to,from,next) => { if (to.name !== 'login') { if (IS_LOGINED) next() else next({ name: 'login' }) } else { if (IS_LOGINED) next({ name: 'home' }) else next() } }) router.afterEach((to, from) => { console.log(from) console.log(to) }) export default router
先用浏览器打开home页面,再跳转到about页面,根据后置守卫中打印出的结果
beforeResolve也是全局守卫,beforeResolve做用于导航被确认以前在全部组件内守卫以及异步路由被解析以后守卫被调用
导航被确认的表示全部导航钩子都结束,则表示导航被确认
路由独享守卫是在路由列表中配置的,例如在home路由中配置一个只在home路由中被调用的守卫
修改src/router/router.js
文件,为home路由添加路由独享守卫
import Home from '@/views/Home.vue' export default [ { path: '/', name: 'home', alias:'/home_page', component: Home, props: route => ({ fruit: route.query.params }), beforeEnter:(to,from,next) => { if(from.name === 'about') alert("这是从about页来的") else alert("这不是从about页来的") next() } }, { path: '/about', name: 'about', component: () => import('@/views/About.vue'), props:{ // fruit:"banana" } },{ path:'/argu/:name', name:'argu', component:() => import('@/views/argu.vue'), props:true },{ path:'/login', name:'login', component:() => import('@/views/login.vue') } ]
此时,用浏览器打开home页,而后跳转到about页,再从about页跳转回到home页
,则会弹出对话框
取消弹出框,在浏览器中输入URL: http://localhost:8080/#/argu/orange
,再从argu页面进入home页面,则会弹出对话框
若是添加了beforeEnter路由独享守卫,在进行逻辑处理后,必定要调用 next()方法,不然不会进行跳转
每个组件均可以有三个钩子
注释其余的守卫,修改src/views/Home.vue
文件,添加组件内守卫
<template> <div class="home"> <b>{{ fruit }}</b> <br> <button @click="handleClick">返回上一页</button> </div> </template> <script> export default { name: 'home', props:{ fruit:{ type: String, default:'strawberry' } }, beforeRouteEnter(to,from,next){ console.log(this) console.log(from.name) console.log(to.name) next() }, methods:{ handleClick () { this.$router.push({ name:`argu`, params:{ name:'banana' } }) } } } </script>
用浏览器打开URL: http://localhost:8080/#/
,而后跳转到About页面,再跳转回Home页
在浏览器的调试页面能够看到
当直接打开Home页面时,from.name的值是null,to.name的值为home 而当从About页面跳转到Home页面时,from.name的值是about,to.name的值仍然是home
组件内守卫是在路由已经被触发,在进入对应页面调用,此时对应页面尚未渲染,因此在组件内守卫中调用this时,是获取不到当前组件的实例的,正如上面的例子里其值为undefined
跟路由独享守卫同样,若是添加了beforeRouteEnter守卫,在进行逻辑处理后,必定要调用 next()方法,不然不会进行跳转
若是想在组件内守卫中获取当前组件的实例,能够在next方法中获取
修改src/views/Home.vue
文件,在组件内守卫的next方法中获取组件实例
<template> <div class="home"> <b>{{ fruit }}</b> <br> <button @click="handleClick">返回上一页</button> </div> </template> <script> export default { name: 'home', props:{ fruit:{ type: String, default:'strawberry' } }, beforeRouteEnter(to,from,next){ next( vm => { console.log(vm) console.log(vm.$root) }) }, methods:{ handleClick () { this.$router.push({ name:`argu`, params:{ name:'banana' } }) } } } </script>
刷新浏览器,打印结果以下
能够经过回调函数的方式来获取当前组件的实例,而后就能够获取某个属性的结果了
修改src/views/Home.vue
文件,添加beforeRouteLeave守卫
<template> <div class="home"> <b>{{ fruit }}</b> <br> <button @click="handleClick">返回上一页</button> </div> </template> <script> export default { name: 'home', props:{ fruit:{ type: String, default:'strawberry' } }, beforeRouteEnter(to,from,next){ next( vm => { console.log(vm) console.log(vm.$root) }) }, beforeRouteLeave(to,from,next){ const is_leave = confirm("您肯定要离开本页面吗?") if(is_leave) next() else next(false) }, methods:{ handleClick () { this.$router.push({ name:`argu`, params:{ name:'banana' } }) } } } </script>
刷新浏览器,显示效果以下
点击About标签后,显示效果以下
点击肯定按钮,页面会跳转到About页面
若是点击取消按钮,则页面不会跳转,仍然会停留在Home页面
在这个守卫被调用时,页面已经渲染好了,因此能够在beforeRouteLeave组件里使用this来获取组件实例
好比咱们一个网页发表一篇博客,当误操做点击跳转到其余页面时,此时就可使用这个守卫来提示用户是否保存当前的编辑内容
修改src/views/argu.vue
文件,添加beforeRouteUpdate守卫
<template> <div> {{ name }} </div> </template> <script> export default { props:{ name:{ type:String, } }, beforeRouteUpdate(to,from,next){ console.log(to.name, from.name) } } </script>
使用浏览器打开URL:http://localhost:8080/#/argu/apple
,此时在浏览器的调试页面不会打印任何数据
修改URL为:http://localhost:8080/#/argu/orange
,页面显示效果以下
第一次进入argu页面时,没有打印任何内容,说明beforeRouteUpdate守卫没有被调用 当路由不改变,路由参数改变时,argu组件被复用,beforeRouteUpdate守卫才被调用
与beforeRouteLeave守卫同样,在beforeRouteUpdate守卫里,页面已经渲染好了,因此可使用this来获取组件实例
导航被触发,不论是使用this.$router.push方式触发,仍是在浏览器中直接输入URL的方式触发, 在失活的组件(即将离开的页面组件)里调用离开守卫 beforeRouteLeave 调用全局的前置守卫 beforeEach 在重用的组件里调用 beforeRouteUpdate 调用路由独享守卫 beforeEnter 解析异步路由组件 在被激活的组件(即将进入的页面组件)里调用beforeRouteEnter 调用全局的解析守卫 beforeResolve 导航被确认 调用全局的后置守卫 afterEash 触发DOM更新 用建立好的实例调用 beforeRouterEnter守卫里传给next的回调函数
路由的切换其实就是一个路由注销,另外一个路由加载
修改src/App.vue
文件,
<template> <div id="app"> <div id="nav"> <router-link v-bind:to="{ name:'home'}">Home</router-link> | <router-link :to="{ name:'about'}">About</router-link> </div> <transition-group name="router"> <router-view key="defalut"/> <router-view key="view1" name="view1"/> <router-view key="view2" name="view2"/> </transition-group> </div> </template> <style lang="less"> .router-enter{ opacity: 0; } .router-enter-active{ transition: opacity 2s ease; } .router-enter-to { opacity:1; } .router-leave{ opacity:1; } .router-leave-active{ transition:opacity 2s ease; } .router-leave-to { opacity:0; } #app { font-family: 'Avenir', Helvetica, Arial, sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; text-align: center; color: #2c3e50; } #nav { padding: 30px; } #nav a { font-weight: bold; color: #2c3e50; } #nav a.router-link-exact-active { color: #42b983; } </style>
刷新浏览器,切换路由时,能够看到路由切换时,页面都有动态效果