脚手架路由实例
index.js
//导入创建路由对象方法和hash 模式路径方法
import { createRouter, createWebHashHistory } from 'vue-router
//创建路由表
const routes = [
{
path: '/',
name: 'Home',
component: () => import('../views/Home.vue'),
}, //path 和 component 必须有
{
path: '/about/:id/:name',
name: 'About',
component: () => import('../views/About.vue')
},
]
//创建路由对象
const router = createRouter({
history: createWebHashHistory(),//hash模式路径
routes//路由表
})
//导出路由对象
export default router
路由连接
路由视图
App.vue
//to属性指定路由路径
Home |
About
//router-view为路由视图
动态路由
指的是:
把Hash 地址中可变的部分
定义为参数项
,从而提高路由规则的复用性
。在vue-router 中使用英文的冒号(:)
来定义路由的参数项。
我们经常需要把某种模式匹配到的所有路由,全都映射到同个组件。
例如,我们有一个About 组件,对于所有 ID 各不相同的用户,都要使用这个组件来渲染。
那么,我们可以在 vue-router 的路由路径中使用“动态路径参数
”来达到这个效果:
index.js 路由表
import About from '../views/About.vue'
{
// 在about组件中,希望根据id和name值展示组件不同的信息
path: '/about/:id/:name', //动态传参
name: 'About',
component: About,
}
App.vue
About
About
当匹配到一个路由时,参数值会被设置到 this.$route.params
,可以在每个组件内通过this.$route.params.xxx
使用路由上的参数。
可以在About组件中输出用户的id和name:
About.vue
About
//在插值表达式中this可以省略
{{$route.params.id}} //001
{{$route.params.name}} //zhangsan 可以直接获取
为了简化路由参数的获取形式,vue-router 允许在路由规则中开启props 传参
。
// 可以为路由规则开启 props 传参,从而方便的拿到动态参数的值
{ path: '/movie/:mid', component: Movie, props: true }
// 接收 props 动态参数的数据
props: ['mid'],
//可以直接使用props里接收的数据
<h3>Movie 组件 --- {{ $route.params.mid }} --- {{ mid }}</h3>
在hash地址中,/
后的参数项,叫做路径参数
在路由的参数对象中,需要使用this.$route.params
获取参数
<router-link to="/about/001/zhangsan">About</router-link>
在hash地址中,?
后的参数项,叫做查询参数
在路由的参数对象中,需要使用this.$route.query
获取参数
<router-link to="/about/001/zhangsan?age=22">About</router-link>
this.$route.fullpath
表示#后的完整路径
/about/001/zhangsan?age=22&color=red
this.$route.path
表示#后的除去查询参数的路径
/about/001
当使用路由参数时,例如从 /user/foo 导航到 /user/bar,原来的组件实例会被复用
。因为两个路由都渲染同个组件,比起销毁再创建,复用则显得更加高效。
不过,这也意味着组件的生命周期钩子不会再被调用。
复用组件时,想对路由参数的变化作出响应的话,你可以简单地 watch (监测变化) $route 对象:
App.vue
watch: {
//时刻监听路由的变化
$route(to, from) {
console.log(to);
console.log(from);
},
},
常规参数只会匹配被 / 分隔的 URL 片段中的字符。如果想匹配任意路径
,vue2使用*
, vue3使用/:pathMatch(.*)
const routes = [
{
//path:"*", //vue2匹配所有路径
path: ' /:pathMatch(.*) ', //vue3 当遇到不认识的路径
name: '404',
component: ()=>import('../views/404.vue') //404路由
},
]
当使用一个通配符时,$route.params 内会自动添加一个名为 pathMatch 参数
。它包含了 URL 通过通配符被匹配的部分
404.vue
404
{{$route.params}}
{{$route.params.pathMatch}}
有时候,同一个路径可以匹配多个路由。
匹配的优先级就按照路由的定义顺序
:
路由定义得越早,优先级就越高
。
在项目中,我们的路由可能会更加复杂,
例如在Home路由中嵌套子路由,分别为HomeA,HomeB三个子模块,则就需要为Home路由添加children属性,并创建Home模块的路由视图。
index.js
//为Home路由添加children属性,添加子路由
const routes = [
{
path: '/',
name: 'Home',
component: Home,
children:[
{path:'/homea',component:()=>import('../views/HomeA.vue')},
{path:'/homeb',component:()=>import('../views/HomeB.vue')}
]
},
]
Home.vue
在浏览器中,点击链接
实现导航的方式,叫做声明式导航。
例如:普通网页中点击
链接、vue 项目中点击
都属于声明式导航
在浏览器中,调用API 方法
实现导航的方式,叫做编程式导航。
例如:普通网页中调用location.href
跳转到新页面的方式,属于编程式导航
除了使用
创建 a 标签来定义导航链接,我们还可以借助 router 的实例方法,通过编写代码来实现。
$router导航对象,包含许多导航的api方法
在 Vue 实例内部,你可以通过 $ router 访问路由实例。 使用this.$router.push(hash地址)
跳转到指定hash 地址,并增加一条历史记录
App.vue
注意:如果提供了 path,params 会被忽略.
跟 router.push 很像,会跳转到指定地址,唯一的不同就是,它不会向 history 添加新记录
,而是跟它的方法名一样 —— 替换掉当前的 history 记录
。
this.$router.replace(hash地址)
this.$router.replace({name:'About',params:{id:'001',name:'zhangsan'}});
//push换为replace,不会添加新的历史记录,将上一个记录替换为现有记录
这个方法的参数是一个整数,意思是在 history 记录中向前或者后退
多少步,类似 window.history.go(n)。
this.$router.go(数值n)
this.$router.go(0); //刷新
this.$router.go(1); //前进
this.$router.go(-1); //后退
如果后退的层数超过上限
,则会原地不动
在实际开发中,一般只会前进和后退一层页面。
因此vue-router 提供了如下两个便捷方法:
$router.back()
在历史记录中,后退到上一个页面
$router.forward()
在历史记录中,前进到下一个页面
注意:在行内使用编程式导航的方法时,this必须要省略,否则会报错。
<!-- 在行内使用编程式导航跳转的时候,this 必须要省略,否则会报错! -->
<button @click="$router.back()">back 后退</button>
<button @click="$router.forward()">forward 前进</button>
通过一个名称来标识一个路由显得更方便一些,特别是在链接一个路由,或者是执行一些跳转的时候。你可以在创建 Router 实例的时候,在 routes 配置中给某个路由设置名称。
About
想同时 (同级) 展示多个视图.
在界面中拥有多个单独命名的视图,而不是只有一个单独的出口。
如果 router-view 没有设置名字,那么默认为 default。
//APP.vue
//路由表
components:{
default:Home,
a:()=>import('../views/HomeA.vue'),
b:()=>import('../views/HomeB.vue')
},
重定向也是通过 routes 配置来完成.
“重定向”的意思是,当用户访问 /a时,URL 将会被替换成 /b,然后匹配路由为 /b.
从/about/:id/:name 重定向到 /
{
path: '/about/:id/:name',
name: 'About',
redirect:'/ ', //重定向 redirect:'/ '
}
重定向的目标也可以是一个命名的路由
{
path: '/about/:id/:name',
name: 'About',
redirect:{name:'Home'}, //重定向 redirect:'/ '
}
/a 的别名是 /b,意味着,当用户访问 /b 时,URL 会保持为 /b,但是路由匹配则为 /a,就像用户访问 /a 一样。
{
path: ‘/about/:id/:name’, //必须传入一个id和name值
name: ‘About’,
alias:‘/ab/:id/:name’, //别名,访问localhost:8081/#/ab/:id/:name时相当于访问about
component: () => import( ‘…/views/About.vue’),
}
在组件中使用 $route 会使之与其对应路由形成高度耦合,从而使组件只能在某些特定的 URL 上使用,限制了其灵活性。
使用$route
路由实例
About
{{$route.params.id}} //001
{{$route.params.name}} //zhangsan 可以直接获取
通过props解耦
路由实例
About
{{name}}
{{id}}
路由表
{
path: '/about/:id/:name', //必须传入一个id和name值
name: 'About',
//另外一种导入路由所需模块的方式(导入需要时使用)
component: () => import( '../views/About.vue'),
props:true, //开启props传参模式 布尔模式
props:{id:456,name:'lisi'}, //开启props传参模式 对象模式 静态传参 id值不能改变,一直为456
props:route=>({id:'$'+route.params.id,name:route.params.name}), //函数模式 可以对收到的参数做处理
},
vue-router 默认 hash 模式(路径带#) —— 使用 URL 的 hash 来模拟一个完整的 URL,于是当 URL 改变时,页面不会重新加载。
如果不想要很丑的 hash,我们可以用路由的 history 模式,需要后台配合。
this.$route
是路由的参数对象,可以拿到参数。
this.$router
是路由的导航对象。
router是VueRouter的一个对象
,通过Vue.use(VueRouter)和VueRouter构造函数得到一个router的实例对象,这个对象中是一个全局的对象,他包含了所有的路由,包含了许多关键的对象和属性。
route是一个跳转的路由对象
,每一个路由都会有一个route对象,是一个局部的对象,可以获取对应的name,path,params,query等。
导航守卫可以控制路由的访问权限。
每次发生路由的导航跳转
时,都会触发全局前置守卫
。
因此,在全局前置守卫中,程序员可以对每个路由进行访问权限的控制
使用 router.beforeEach
注册一个全局前置守卫
index.js
const router = new VueRouter({...})
// 为 router 实例对象,声明全局前置导航守卫
// 只要发生了路由的跳转,必然会触发 beforeEach 指定的 function 回调函数
router.beforeEach(function(to, from, next) {
// to 表示将要访问的路由的信息对象
// from 表示将要离开的路由的信息对象
// next() 函数表示放行的意思
// 分析:
// 1. 要拿到用户将要访问的 hash 地址
// 2. 判断 hash 地址是否等于 /main。
// 2.1 如果等于 /main,证明需要登录之后,才能访问成功
// 2.2 如果不等于 /main,则不需要登录,直接放行 next()
// 3. 如果访问的地址是 /main。则需要读取 localStorage 中的 token 值
// 3.1 如果有 token,则放行
// 3.2 如果没有 token,则强制跳转到 /login 登录页
if (to.path === '/main') {
// 要访问后台主页,需要判断是否有 token
const token = localStorage.getItem('token')
if (token) {
next()
} else {
// 没有登录,强制跳转到登录页
next('/login')
}
} else {
next()
}
})
//以判断用户是否登录为例
router.beforeEach((to, from, next) => {
if(cookie.get('login'))
next()
else{
if (to.path !== "/login") {
next({ path: "/login" });
} else {
next();
}
}
})
每个守卫方法接收三个参数
:
to
: Route: 即将要进入的目标 路由对象
from
: Route: 当前导航正要离开的路由
next
: Function: 执行效果依赖 next 方法的调用参数。表示允许放行。一定要调用一次next()
当前用户拥有后台主页的访问权限,直接放行:next()
当前用户没有后台主页的访问权限,强制其跳转到登录页面:next('/login')
当前用户没有后台主页的访问权限,不允许跳转到后台主页:next(false)
(强制处于当前页面)
用 router.beforeResolve 注册一个全局守卫。这和 router.beforeEach 类似,区别是在导航被确认之前,同时在所有组件内守卫和异步路由组件被解析之后,解析守卫就被调用。
注册全局后置钩子,然而和守卫不同的是,这些钩子不会接受 next 函数也不会改变导航本身,导航被确认后,全局后置钩子被调用
router.afterEach((to, from) => {
// ...
})
在路由配置上直接定义 beforeEnter 守卫,在全局前置守卫触发后, beforeEnter 守卫被调用
const router = new VueRouter({
routes: [
{
path: '/foo',
component: Foo,
beforeEnter: (to, from, next) => {
// ...
}
}
]
})
可以在路由组件内直接定义以下路由导航守卫
beforeRouteEnter(to, from, next) {
// 在渲染该组件的对应路由被 confirm 前调用
// 不!能!获取组件实例 `this`
// 因为当守卫执行前,组件实例还没被创建
},
beforeRouteUpdate(to, from, next) {
// 举例来说,对于一个带有动态参数的路径 /foo/:id,在 /foo/1 和 /foo/2 之间跳转的时候,
// 由于会渲染同样的 Foo 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。
// 可以访问组件实例 `this`
},
beforeRouteLeave(to, from, next) {
// 导航离开该组件的对应路由时调用
// 可以访问组件实例 `this`
}
定义路由的时候可以配置 meta 字段。
一个路由匹配到的所有路由记录会暴露为 $route 对象的 $route.matched 数组。
需要遍历 $route.matched 来检查路由记录中的 meta 字段。
//路由表
meta: { requiresAuth: true }
//About.vue
{{$route.matched[0].meta}}
//app.vue
//CSS
#nav a.router-link-exact-active{color:#42b983;}
.fade-enter-active,.fade-leave-active{transition: opacity .5s;}
.fade-enter,.fade-leave-to{opacity: 0;}
scrollBehavior (to, from, savedPosition) {
return { left: 0, top: 0 }
//vue2 {x:0,y:0}
}