vue 路由(二)-- 进阶
- 路由向组件传递参数
- 传参方式
- `:` 在路径传递参数
- `params` + `name` 传递参数
- query 参数
- props 接收路由的 `params`
- 完整的例子
- HTML5 History 模式
- meta 元信息
- 导航守卫
- 全局守卫
- 过渡效果
- 参考
路由可向路由匹配的组件传递参数, 不同情况
向组件传递不同的参数,从而实现组件的复用。
路由向组件传递参数
和路由匹配的组件可以在组件中使用 $route
获取路由上的参数:
传参方式
:
、 params
和 query
:
在路径传递参数
{path: "/argu/:id/book",name: "argu",component: () => import("@/views/ArguPage")
}
路径
中的一部分是参数, 必须
传递该参数:
<!--路径跳转-->
<router-link to="/argu/123/book">path跳转</router-link>
<!--路由名跳转-->
<router-link :to="{name:'argu',params:{id:'test'}}" tag="button">name+params跳转</router-link>
<!--获取参数-->
<h1>{{$route.params.id}}</h1>
<!--params的名字路径中的的参数名一致-->
此时 path
+ parmas
传递参数, params
会被忽略。
params
+ name
传递参数
路由:
{path: "/argu",name: "argu",component: () => import("@/views/ArguPage")
}
跳转方式是 name
+ params
+(query),通过 path
跳转,params 会被忽略。
<router-link :to="{name:'argu', params:{name:'hangge'}}">跳转到 hello</router-link>
<!-- path + params ,params 会被忽略,因为路径中没有定义参数 -->
<router-link :to="{path:'/argu', params:{name:'hangge'}}">跳转到 hello</router-link>
query 参数
query 参数,表现为查询字符串,和 location.search
一样的。
不需要先在路径中先定义,可通过 path
、 path
+ query
或者 name
+ query
传递参数。
<router-link to="/argu?queryName=value">跳转到 hello</router-link>
<router-link :to="{path:'/argu',query:{queryName:value}}">跳转到 argu</router-link>
<router-link :to="{name:'argu',query:{queryName:value}}">跳转到 argu</router-link>
<h1>{{ $route.query.queryName }}</h1>
函数传递 query
// 注意是 $router 不是 $route
go() {this.$router.push({name: 'argu',query: {queryName: "你好"}})
}
但是这样使得 $route
和组件耦合在一起,不方便组件的复用,如果能将路由中的参数传递到组件的 props
就好了,恰恰是可以这样设置的。
props 接收路由的 params
路由传参数的三种方式:
- 布尔模式
{path: '/user/:id',component: User,props: true //表明 将 id 作为 props 传递到匹配的组件 User 中。
}
User 中定义 props 接收 id:
export default {props: {id: {type: String,default: 'jackZhou' //默认值}}
}
- 对象模式
将路由的 props
属性设置一个对象,也可在组件中获取到该值,这种方式往往用于传递静态值,即 name 值不会变化。
路由对象:
{name: 'home',alias: '/home_page',path: '/',props: {name: 'jack jack'},component: Home
}
Home 组件:
props: {name: {type: String,}
}
- 函数模式
以上两种方式,params 参数的名字必须和组件中的 props 属性名字相同,如果想对 params 进行改造后传递到组件,就可将 props
设置成函数,在函数内获取路由中的 params 或者 query,或者其他属性值,对其进行处理后再传递给组件。
注意:这种方式函数必须返回一个对象。
路由:
{name: 'about',path: '/about/:years', //params 有一个参数 yearsprops: (route) {const now = new Date()return {// 将 years 改造成 namename: (now.getFullYear() + parseInt(route.params.years)) + '!'}},component: () => import('@/views/AboutPage'),
}
组件中的 props:
props: {name: {type: String}
}
命名视图的路由,要为每个命名视图添加 props
:
{path: '/name/:view',name: 'name_view',components: {default: () => import('@/views/ChildPage'),sister: () => import('@/views/SisterPage'),brother: () => import('@/views/BrotherPage'),},props: {default: true,sister: false,brother: (route) => ({view: route.params.view.toUpperCase()})}
}
完整的例子
route 的 params 传递参数 – codepen
HTML5 History 模式
路由配置里有一个属性 mode
,默认值是 hash
,以 hash 来模拟一个 url,url 改变时,页面不会重新加载。
先使用普通模式,可将 mode
设置成 history
,这种模式会使用 history.pushSate
来完成 url 跳转而页面不会重新加载。这种模式需要服务器设置一下。
使用 history 模式,因为 web 应用往往是单页应用,当用户访问一个不存在的路径时,需要提供一个后备页面。
在路由配置的最后增加一个 404 路由:
{path: '*',component: NotFoundPage // 前面没有匹配的路由,最后会匹配该路由。
}
meta 元信息
可在路由对象中配置 meta
属性,meta 是一个对象。
比如,根据不同页面显示不同的 title。
{name: "about",path: "/about",meta: {title: "关于"},component: () => import("@/views/AboutPage")
}
在路由配置文件中,设置各个页面的 title:
const router = new Router({routes
})
router.beforeEach((to, from, next) => {//setTitle 函数用于设置页面标题to.meta && setTitle(to.meta.title) //这是简化if语句的简写console.table(to)console.table(from)next()
})
export default router
导航守卫
全局守卫
- 全局前置守卫
const router = new Router({{path: "/",name: "heom_page"component: Home,// 路由独享守卫beforeEnter: (to, from, next) => {// 处理逻辑next()}}
})
//每次路由进入都会调用
router.beforeEach((to, from, next) => {//处理逻辑,比如登录判断,可跳转到任意页面//不要忘记调用 next,不调用 next,页面不会跳转
})
- 后置钩子
//路由跳转之后做一些操作,比如去掉登录样式
router.afterEach((to, form) => {//逻辑处理
})
-
路由独享守卫
只在匹配某个路由时执行。 -
组件内守卫
beforeRouteEnter
, 组件创建之前调用,组件不具备 this
;
beforeRouteUpdate
,路由更新,而组件被复用时调用,可使用 this
;
beforeRouteLeave
,离开路由时调用,可使用 this
。
export default {name: 'Home',data() {return {}},/*** 组件内路由守卫* 1. 该函数在路由进入时执行* 2. 此时组件还未渲染,不可用 this, 当可在 next 中用 vm* 3. next 晚于 mounted 执行,next 之前的代码,早于 beforeCreate 执行* 4. 最后需要调用 next 使得路由跳转*/beforeRouteEnter(to, from, next) {console.log('①,home 组件内路由守卫,beforeRouteEnter')// next 晚于 mounted 执行,next 之前的代码,早于beforeCreate 执行next(vm => {console.log('vm')console.log(vm) //有值console.log('this')console.log(this) // undefinedconsole.log('②,home 组件内路由守卫,beforeRouteEnter')})},/*** 组件内路由守卫* 1. 该函数在路由离开时执行,最先调用,然后再调用全局守卫,再调用 beforeDestroy* 2. 此时,该路由守卫所在组件已渲染,可用 this* 3. 最后需要调用 next 使得路由跳转*/beforeRouteLeave(to, from, next) {console.log('①,home 组件内路由守卫,beforeRouteLeave')let leave = confirm('你确定要离开 home 页吗?')if (leave) {// console.log(to.name, from.name);// console.log(this);next(() => {console.log('②,home 组件内路由守卫,beforeRouteLeave')}) //给 next 传递 false ,路由不会跳转} else {next(false)}},/** 当路由发生变化,而组件被复用时调用* 1. 此时该复用组件已被渲染,可用 this* 2. 需要调用 next,组件才能渲染*/beforeRouteUpdate(to, from, next) {console.log('①,argu,组件内路由守卫,beforeRouteUpdate')next(() => {console.log('next,argu,组件内路由守卫,beforeRouteUpdate')})},beforeCreate() {console.log('beforeCreate')},created() {console.log('created')},beforeMount() {console.log('beforeMount')},mounted() {console.log('mounted')},beforeUpdate() {console.log('beforeUpdate')},updated() {console.log('updated')},beforeDestroy() {console.log('beforeDestroy')},destroyed() {console.log('destroyed')}
}
路由全过程:
- 导航被触发
- 离开页面(失活的组件)里调用离开守卫 beforeRouteLeave
- 调用
全局前置守卫
beforeEach - 在重用的组件里调用 beforeRouteUpdate (非重用组件,没有这个步骤)
- 调用路由独享守卫 beforeEnter
- 解析异步路由组件
- 在进入页面(激活组件)调用 beforeRouteEnter
- 调用
全局解析守卫
beforeResolve (导航被确认之前,组件内守卫和异步路由组件被解析之后,调用 beforeResolve) - 导航被确认(什么时候被确认,全部钩子执行完了,是被确认的)
- 调用
全局后置守卫
afterEach - 触发 DOM 更新
- 在 vue 实例中(此时页面解析完毕了吗?是的)调用 beforeRouterEnter 守卫里传给 next 的回调。
next
在mounted
之后被调用。
过渡效果
可以给路由匹配的组件设置过渡效果,让页面平滑地显示,提升用户体验。
需要用到 transition
标签,如果有多个视图需要过渡,则用 transition-group
。
<transition-group name="router-view"><!-- 视图渲染组件,该组件内不需要房子任何内容,可写成只闭合标签--><router-view key="default" /><!-- 有多个路由视图需要匹配,则用命名视图 --><router-view key="sister" name="sister"></router-view><router-view key="brother" name="brother"></router-view>
</transition-group>
css 过渡效果:
.router-view-enter {opacity: 0;
}.router-view-enter-active {transition: opacity 1s ease;
}.router-view-enter-to {opacity: 1;
}.router-view-leave {opacity: 1;
}.router-view-leave-active {transition: opacity 1s ease;
}.router-view-leave-to {opacity: 0;
}
这些设置,每个页面的效果都是一样的,要为不同的页面设置不同的效果,可用路由传递相应的参数来,让动态绑定到 transition 的 name 属性上。
或者监听路由变化:
watch: {'$route'(to) {console.log(to);to.params && to.params.view && (this.effect = to.params.view)},
}
参考
Vue.js - 路由 vue-router 的使用详解 2(参数传递)