文章目录
一、路由组件传参:
1. 布尔模式
- /view/argu.vue
<template>
<div>
<!--$route代表当前加载的路由对象,包含params参数,它是一个对象,里面包含一个叫做name的值-->
{{ name }}
</div>
</template>
<script>
export default {
props: {
name: {
type: String,
default: 'sun'
}
}
}
</script>
- /router/router.js
{
// 动态路由参数,不管参数是什么,匹配到的都是这个路由对象
path: '/argu/:name',
name: 'argu',
component: () => import('@/views/argu.vue'),
// true表示里面的参数,它会使用router的params作为组建的属性,此时params中
// 有一个name('/argu/:name'),它就会把name传入argu的属性里
props: true
},
2. 普通页面模式
- /view/About.vue
<template>
<div class="about">
<h1>This is an about page</h1>
<b>{{ food }}</b>
</div>
</template>
<script>
export default {
props: {
food: {
type: String,
default: 'apple'
}
}
}
</script>
- /router/router.js
{
path: '/about',
name: 'about',
// route level code-splitting
// this generates a separate chunk (about.[hash].js) for this route
// which is lazy-loaded when the route is visited.
// 懒加载
component: () => import(/* webpackChunkName: "about" */ '@/views/About.vue'),
props: {
food: 'banana'
}
}
3. 函数模式
- router/router.js
{
path: '/',
// 定义别名
alias: '/home_page',
name: 'home',
component: Home,
// 函数模式
props: router => {
}
}
- /views/Home.vue
<template>
<div class="home">
<b>{{ food }}</b>
<img alt="Vue logo" src="../assets/img/logo.png">
<HelloWorld msg="Welcome to Your Vue.js App"/>
<button @click="handleClick('back')">返回上一页</button>
<button @click="handleClick('push')">跳转parent</button>
<button @click="handleClick('replace')">替换到parent</button>
</div>
</template>
<script>
// @ is an alias to /src
import HelloWorld from '@/components/HelloWorld.vue'
export default {
name: 'home',
components: {
HelloWorld
},
props: {
food: {
type: String,
default: 'apple'
}
},
methods: {
handleClick(type) {
// 路由实例,可在main.js中进行查看,此处-1为返回上一页,1为返回下一页 back()功能相同
if (type === 'back') this.$router.back() // this.$router.go(-1)
else if (type === 'push') {
const name = 'sun'
// this.$router.push('/parent')
this.$router.push({
// name可以把参数带过去,而path不能
path: `/argu/${name}`
// name: 'argu',
// params: {
// name: 'sun'
// }
// name: 'parent',
// query: {
// // 在地址后面会多一个参数:http://localhost:8080/#/parent?name=sun
// name: 'sun'
// }
})
}
else if (type === 'replace')
this.$router.replace({
name: 'parent'
})
}
}
}
</script>
网址 : http://localhost:8080/#/?food=banana
- 结果如图:
二、html5 history模式
- 使用history的一些api来做无刷新页面的一些跳转,没有#
如果使用history模式,所有匹配不到url的静态资源都会指向index.html
应该在router.js里面增加一个匹配所有路径的路由 - router/index.js
import Vue from 'vue'
import Router from 'vue-router'
import routes from './router'
// Router作为一个插件,需要使用Vue.use()方式将其加载进来
Vue.use(Router)
// Router有两个参数:routes和mode
export default new Router({
// 模式
// 在url的# 号后面作变化,页面是不会刷新的
// mode: 'hash',
/* 使用history的一些api来做无刷新页面的一些跳转,没有#
如果使用history模式,所有匹配不到url的静态资源都会指向index.html
应该在router.js里面增加一个匹配所有路径的路由 */
mode: 'history',
// 路由
routes: routes
})
- router/router.js
// 根据优先级原则,定义在越上面的,优先级越高,因此,应该定义在最下面
{
path: '*',
component: () => import('@/views/error_404.vue')
}
- views/error_404.vue
<template>
<div>
404
</div>
</template>
<script>
export default {
name: ""
}
</script>
<style scoped>
</style>
三、导航守卫
完整的导航解析流程:
1.导航被触发
2.在失活的组件(即将离开的页面组件)里调用离开守卫 beforeRouteLeave
3.调用全局的前置守卫 beforeEach
4.在重用的组件里调用 beforeRouteUpdate
5.调用路由独享
6.解析异步路由组件
7.在被激活的组件(即将进入的页面组件)里调用 beforeRouteEnter
8.调用全局解析守卫 beforeResolve
9.导航被确认
10.调用全局的后置守卫 afterEach
11.触发DOM更新
12.用创建好的实例调用beforeRouterEnter守卫里传给next的回调函数
1. 全局守卫
1)router.beforeEach : 全局前置守卫
- router/router.js
{
path: '/login',
name: 'login',
component: () => import('@/views/login.vue')
},
- router/index.js
import Vue from 'vue'
import Router from 'vue-router'
import routes from './router'
// Router作为一个插件,需要使用Vue.use()方式将其加载进来
Vue.use(Router)
// 拎出来单独定义
const router = new Router({
routes
})
const HAS_LOGINED = true
// 注册一个全局前置守卫
// to,from,next都是路由对象,to代表即将跳转的页面,from是即将离开的路由对象,next是一个函数
router.beforeEach((to, from, next) => {
if (to.name !== 'login') {
// 如果已经登陆则跳转
if (HAS_LOGINED) next()
// 如果为登陆,则先登录,里面可以传入name对象,或path,或路径
else next({ name: 'login' })
} else {
if (HAS_LOGINED) next({ name: 'home' })
else next()
}
})
// Router有两个参数:routes和mode
// 模式
// 在url的# 号后面作变化,页面是不会刷新的
// mode: 'hash',
/* 使用history的一些api来做无刷新页面的一些跳转,没有#
如果使用history模式,所有匹配不到url的静态资源都会指向index.html
应该在router.js里面增加一个匹配所有路径的路由 */
// mode: 'history',
// 路由
export default router
- views/login.vue
<template>
<div>
Login page
</div>
</template>
<script>
export default {
name: ""
}
</script>
<style scoped>
</style>
2)后置钩子
- router/index.js
// 后置钩子,在路由跳转之后进行一些操作,它不能对跳转的页面进行操作,控制,它只是能够处理一些简单逻辑
router.afterEach((to, from) => {
// logining = false
})
2. 专供于页面的守卫
1)beforeRouteEnter
- views/Home.vue
- beforeRouteEnter : 组件在确认前被调用
import Home from '@/views/Home'
export default [
{
path: '/',
// 定义别名
alias: '/home_page',
name: 'home',
component: Home,
// 函数模式 route为参数,代表当前路由对象 如果想要返回一个对象,则以这种方式填写:({})
props: route => ({
food: route.query.food
}),
// 专供于home页的守卫
// to,from,next都是路由对象,to代表即将跳转的页面,from是即将离开的路由对象,next是一个函数
beforeEnter: (to, from, next) => {
if (from.name === 'about') alert('这是从about来的')
else alert('这不是从about来的')
// 注意调用next()跳转页面
next()
}
},
{
path: '/login',
name: 'login',
component: () => import('@/views/login.vue')
},
{
path: '/about',
name: 'about',
// route level code-splitting
// this generates a separate chunk (about.[hash].js) for this route
// which is lazy-loaded when the route is visited.
// 懒加载
component: () => import(/* webpackChunkName: "about" */ '@/views/About.vue'),
props: {
food: 'banana'
}
},
{
// 动态路由参数,不管参数是什么,匹配到的都是这个路由对象
path: '/argu/:name',
name: 'argu',
// 参数
params: {
name: 'lison'
},
component: () => import('@/views/argu.vue'),
// true表示里面的参数,它会使用router的params作为组建的属性,此时params中
// 有一个name('/argu/:name'),它就会把name传入argu的属性里
props: true
},
// 嵌套路由
{
path: '/parent',
name: 'parent',
component: () => import('@/views/parent.vue'),
// children代表着嵌套在parent里面的子集页面,路径不用写斜线,作为子集会自动补全
children: [
{
path: 'child',
component: () => import('@/views/child.vue')
}
]
},
{
path: '/named_view',
// 注意有个s
components: {
// 没有命名则加载default
default: () => import('@/views/child.vue'),
email: () => import('@/views/email.vue'),
tel: () => import('@/views/tel.vue')
}
},
// 重定向路由
{
path: '/main',
// redirect: '/'
// redirect: to => {
// console.log(to)
// }
// redirect: 'home'
// redirect: to => {
// return {
// name: 'home'
// }
// }
redirect: to => {
return '/'
}
},
// 根据优先级原则,定义在越上面的,优先级越高,因此,应该定义在最下面
{
path: '*',
component: () => import('@/views/error_404.vue')
}
]
- views/Home.vue : 打印出当前所有实例
// 组件在确认前被调用
beforeRouteEnter(to, from, next) {
next(vm => {
// 打印出当前所有实例
console.log(vm);
})
// 跳转至下一页
next()
},
2) 页面后置钩子:beforeRouteLeave
- src/views/Home.vue :页面后置钩子
// 页面后置钩子
beforeRouteLeave(to, from, next) {
const leave = confirm('您确定要离开吗?')
if (leave) next()
else next(false)
},
- src/views/argu.vue : 在路由发生变化,组件被复用的情况时被调用
<template>
<div>
<!--$route代表当前加载的路由对象,包含params参数,它是一个对象,里面包含一个叫做name的值-->
{{ name }}
</div>
</template>
<script>
export default {
props: {
name: {
type: String,
default: 'sun'
}
},
// 在路由发生变化,组件被复用的情况时被调用
beforeRouteUpdate(to, from, next) {
console.log(to.name,from.name);
}
}
</script>
四、路由源信息
meta里面可以存放一些需要定义的信息,比如页面是否需要一些权限,或者一些其他信息,然后在路由前置守卫里做一些处理。
- 以下是一个更改about的title为“关于”,其他页面为“admin”的例子:
- src/lib/util.js
export const setTitle = (title) => {
window.document.title = title || 'admin'
}
- src/router/router.js
{
path: '/about',
name: 'about',
// route level code-splitting
// this generates a separate chunk (about.[hash].js) for this route
// which is lazy-loaded when the route is visited.
// 懒加载
component: () => import(/* webpackChunkName: "about" */ '@/views/About.vue'),
props: {
food: 'banana'
},
meta: {
title: '关于'
}
},
- src/router/index.js
// 注册一个全局前置守卫
// to,from,next都是路由对象,to代表即将跳转的页面,from是即将离开的路由对象,next是一个函数
router.beforeEach((to, from, next) => {
to.meta && setTitle(to.meta.title)
if (to.name !== 'login') {
// 如果已经登陆则跳转
if (HAS_LOGINED) next()
// 如果为登陆,则先登录,里面可以传入name对象,或path,或路径
else next({ name: 'login' })
} else {
if (HAS_LOGINED) next({ name: 'home' })
else next()
}
})
五、路由的切换动效
页面的切换就是一个组件注销,一个组件加载,在vue基础里面有提到组件的过渡,能够为一个组件的显示
和隐藏都设置一个过度效果,同样也能为一个页面设置一个过渡效果。多个组件使用过渡效果需要使用
<transition-group></transition-group>
(只需要包住一个视图渲染组件则只需要)包住视图渲染组件<router-view/>
1. 所有页面动效
- src/App.vue
<!--一个示例,即运行vue时的页面-->
<template>
<div id="app">
<div id="nav">
<!--封装了一个a标签,里面有一个重要属性:to,它指定的值是一个路径-->
<router-link v-bind:to="{name: 'home'}">Home</router-link> |
<!--命名路由,可以通过指定name来跳转到相应界面-->
<router-link v-bind:to="{name: 'about'}">About</router-link>
</div>
<transition-group name="router">
<!--是一个视图渲染组件-->
<router-view key="default"/>
<!--命名视图-->
<router-view name="email" key="email"/>
<router-view name="tel" key="tel"/>
</transition-group>
</div>
</template>
<style lang="less">
/*可以通过css来制作添加动态效果*/
/*首先设置页面进入的效果*/
/*router-enter代表页面没有显示,但即将显示的状态*/
.router-enter {
/*设置透明度为零*/
opacity: 0;
}
/*设置组件从没有到有的过程的动态的效果*/
.router-enter-active {
/*使用transition来给opacity添加效果,时间设置1s ease效果*/
transition: opacity 1s ease;
}
/*router-enter-to来设置页面完全显示之后的效果 让其透明度变为1*/
.router-enter-to {
opacity: 1;
}
/*在此处设置页面离开的效果*/
.router-leave {
/*设置透明度为零*/
opacity: 1;
}
/*设置组件从没有到有的过程的动态的效果*/
.router-leave-active {
/*使用transition来给opacity添加效果,时间设置1s ease效果*/
transition: opacity 1s ease;
}
/*router-enter-to来设置页面完全显示之后的效果 让其透明度变为1*/
.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;
a {
font-weight: bold;
color: #2c3e50;
&.router-link-exact-active {
color: #42b983;
}
}
}
</style>
2. 单独页面动效
- src/App.vue
<!--一个示例,即运行vue时的页面-->
<template>
<div id="app">
<div id="nav">
<!--封装了一个a标签,里面有一个重要属性:to,它指定的值是一个路径-->
<router-link v-bind:to="{name: 'home'}">Home</router-link> |
<!--命名路由,可以通过指定name来跳转到相应界面-->
<router-link v-bind:to="{name: 'about'}">About</router-link>
</div>
<transition-group :name="routerTransition">
<!--是一个视图渲染组件-->
<router-view key="default"/>
<!--命名视图-->
<router-view name="email" key="email"/>
<router-view name="tel" key="tel"/>
</transition-group>
</div>
</template>
<script>
export default {
watch: {
// 监听路由对象的变化,to代表当前路由对象
'$route' (to) {
// 先判断to里是否有query字段 && 在to的query里找专门为这个页面设置的动效的name值 && 如果前面的
//都满足,则将routerTransition改为query里的transitionName
// 通过http://localhost:8080/#/about?transitionName=router 将transitionName=router
//传入query,就有了动效
to.query && to.query.transitionName && (this.routerTransition = to.query.transitionName)
}
}
}
</script>
<style lang="less">
/*可以通过css来制作添加动态效果*/
/*首先设置页面进入的效果*/
/*router-enter代表页面没有显示,但即将显示的状态*/
.router-enter {
/*设置透明度为零*/
opacity: 0;
}
/*设置组件从没有到有的过程的动态的效果*/
.router-enter-active {
/*使用transition来给opacity添加效果,时间设置1s ease效果*/
transition: opacity 1s ease;
}
/*router-enter-to来设置页面完全显示之后的效果 让其透明度变为1*/
.router-enter-to {
opacity: 1;
}
/*在此处设置页面离开的效果*/
.router-leave {
/*设置透明度为零*/
opacity: 1;
}
/*设置组件从没有到有的过程的动态的效果*/
.router-leave-active {
/*使用transition来给opacity添加效果,时间设置1s ease效果*/
transition: opacity 1s ease;
}
/*router-enter-to来设置页面完全显示之后的效果 让其透明度变为1*/
.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;
a {
font-weight: bold;
color: #2c3e50;
&.router-link-exact-active {
color: #42b983;
}
}
}
</style>