1.入门
理解:
1.Vue-Router是Vue.js官方的路由插件,它和vue.js是深度集成的,适用于构建单页面应用。vue的单页面应用是基于路由和组件的,路由用于设定访问路径,并将路径和组件映射起来。传统的页面应用,是用一些超链接实现页面切换和跳转的。在vue-router中,则是路径之间的切换,也就是组件间的切换。路由模块的本质 就是建立起url和页面之间的映射关系。
因为Vue做的是单页应用,就相当于只有一个主的index.html页面==>a标签不起作用
2.route,routes,router
route:首先它是个单数,我们可以理解为单个或某个路由
routes:它是个复数,表示多个集合才能为复数,即我们可以理解为多个路由的集合,routes表示多个数组的集合。
router:这个是路由器,用于管理上面两个路由,路由器会去路由集合中找对应的路由
代码:
<div id="app">
//1.router-link 中用于进行导航 to用于指定链接
//2.router-view 是路由出口 显示router-link中的url对应的组件
<router-link to="/">go to Home</router-link>
<router-link to="/about">go to About</router-link>
<router-view></router-view>
</div>
//1.定义一些路由组件,也可以从其他文件中导入
const Home={template:'<div>Home</div>'},
const About={template:'<div>About</div>'}
//2.定义一些路由 每个路由都需要映射到一个组件
const routes=[
{path:'/',component:Home},
{path:'/about',component:About},
]
//3.创建路由实例并传递'routes'配置
const router=VueRouter.createRouter({
//4.内部提供了history模式的实现
history:VueRouter.createWebHasHistory(),
routes,
})
//5.创建并挂载根实例
const app = Vue.createApp({})
//6.通过调用app.use(router)使得我们可以在任意组件中以this.$router形式访问它,并且以this.$routes的形式访问当前路由
app.use(router)
app.mount('#app')
2.动态路由匹配
1.带参数的动态路由匹配
需要将给定匹配模式的路由映射到同一个组件
比如说:有一个User组件,它应该对所有的用户进行渲染,但是用户Id不同 因此在VueRouter中,我们可以使用一个动态字段来实现 ==>路径参数
const User = {
template:'<div>User</div>',
}
const routes = [
{path:'/users/:id',component:User},
]
动态字段以:开始,路径参数用:表示。当一个路由被匹配时,它的params的值将在每个组件中
this.$route.params的形式暴露出来 ==>可以通过更新User的模板来呈现当前用户的ID
const User = {
template:'<div>User{{$route.params.id}}</div>'
}
2.响应路由参数的变化:
使用带有参数的路由时需要注意的是,当用户从/users/johnny导航到/users/jolyne时,相同的组件实例将被重复使用,因为两个路由都渲染同个组件,比起销毁再创建,复用更加高效。但是这意味这组件的生命周期钩子函数不会被调用。
const User = {
template:'...',
created(){
this.$watch(
//要对同一个组件中的参数变化做出响应,可以简单的watch $route对象上的任意属性
() =>this.$route.params,
(toParams,previousParam)=>{
//对路由变化做出响应
}
)
}
}
3.嵌套路由:
<div id="app">
<router-view></router-view>//这里的router-view是顶层
</div>
对应的路由组件
const User = {
template:'
<div>
<h2>User{{$route.param.id}}</h2>
<router-view></router-view>//这里是app渲染的组件在渲染下一层组件
</div>'
}
const routes = [{path:'/user/:id',component:User}]
要想实现路由组件,要在路由中配置childeren:
const routes = [
{
path:'/user/id',
components:User,
children:[
{
path:'profile',
component:UserProfile,
},
{
path:'posts',
component:UserPosts,
},
],
},
]
注意:以/开头的嵌套路劲将被视为根路径 这允许你利用组件嵌套 而不必使用url
还有一些vue-router低级部分没有看 比如vue-router命名等 这个没必要看 看了也不记得 直接用就好
4.导航守卫
Vue 导航守卫_许你今世繁华的博客-CSDN博客_vue导航守卫
vue导航守卫_摩羯座**的博客-CSDN博客_vue导航守卫
VueRouter提供的导航守卫主要用于在导航的过程中重定向或取消路由,或添加权限验证,数据获取等业务逻辑===>监听每一个路由跳转的过程,然后提供一些钩子函数让你有机会在跳入过程中植入相关信息
导航守卫的分类(这三个守卫可以用于路由导航过程中的不同阶段):
- 全局守卫(全局前置守卫,全局解析守卫,全局后置钩子)
- 路由守卫(路由独享守卫)
- 组件内守卫(加载,离开,更新)
每一个导航守卫都有三个参数:to、from和next。
- to:表示即将进入的目标路由对象
- from:当前导航正要离开的路由对象
- next:函数,以下是next的常用方法
- next(): 进行管道中的下一个钩子
- next(false): 中断当前导航
- next( ./xx ): 中断当前导航,并跳转至设置好的路径
1.全局前置守卫:
当一个导航触发时,全局前置守卫按照创建的顺序调用。守卫可以是异步解析执行,此时导航在所有守卫解析完之前一直处于挂起状态。全局前置守卫使用router.beforeEach()注册
特点:可以拦截页面跳转
执行时间:在页面跳转完成之前
参数:to表示即将前往页面对应的路由对象,系统自动注入 // from 表示即将离开页面的路由对象,系统自动注入
const router = new VueRouter({....});
router.beforeEach((to,from,next)=>{
// 用户验证登录身份
if (to.name != 'Login' && !isAuthenticated) next({ name: 'Login' })
else next();
})
2.全局解析守卫
全局解析守卫是vue-router2.5.0版本新增的,使用【router.beforeResolve】注册。它和【router.beforeEach】类似,区域在于,在导航被确认之前,在所有组件内守卫和异步路由组件被解析之后,解析守卫被调用。
特点:可以拦截页面跳转
执行时间:在页面跳转完成之前
参数:to 表示即将前往页面对应的路由对象,系统自动注入// from 表示即将离开页面的路由对象,系统自动注入 // next 路由跳转方法
const router = new VueRouter({....});
router.beforeResolve((to,from,next)=>{
//这里执行具体操作
//next 调用
if(to.meta.verification){
try {
// 验证正确
await askForPage()
}catch(error) {
// 验证错误,取消导航
return false
}
}
}
3.全局后置钩子
全局后置钩子使用【router.afterEach】注册,它在导航被确认之后调用。
参数:to 表示即将前往页面对应的路由对象,系统自动注入// from 表示即将离开页面的路由对象,系统自动注入
const router = new VueRouter({....});
router.afterEach((to,from)=>{
//这里执行具体操作
})
4.路由守卫
路由独享守卫是在routes配置的路由对象中直接定义的beforeEnter守卫。
路由独享守卫只在进入路由时触发,参数改变时不会触发,它们只有在从一个不同的路由导航时,才会被触发
const router = new VueRouter({
routes: [
{
path: '/foo',
component: Foo,
beforeEnter: (to, from, next) => {
// ...
}
}
]
})
5.组件内守卫
共有三个组件内守卫:beforeRouteEnter、beforeRouterUpdate和beforeRouteLeave。
注意:
beforeRouterEnter守卫不能访问this,因为在守卫是在导航确认前被调用,这时新进入的组件实例还没有被创建。
不过beforeRouteEnter有一个特权,就是它的next函数支持回调,而其他的守卫则不行。可以把组件实例作为回调方式的参数,在导航被确认后执行回调,而这个时候,组件实例已经创建完成。利用这个特性,可以将created钩子用beforeRoute守卫来替换
//
const book = {
template:"...",
beforeRouteEnter (to, from, next) {
//在渲染该组件的路由被确认之前调用
//不能通过this来访问组件实例,因为在守卫执行前,组件实例还没有被创建
},
beforeRouteUpdate (to, from, next) {
//在渲染该组件的路由改变,但是该组件被复用时调用
//例如,对于一个带有动态参数的路由 /foo/:id,在/foo/1和/foo/2之间跳转的时候
//相同的foo组件实例将会被复用,而这个守卫就会在这种情况下被调用。
//可以访问组件实例的this
},
beforeRouteLeave (to, from, next) {
//导航即将离开该组件的路由时调用
//可以访问组件实例的this
}
}
5.路由元信息
将任意信息附加到路由上,如过渡名称,谁可以访问路由等
const routes = [
...
meta:{
//任何人都可以阅读文章
requiresAuth:false
}
]
6.数据获取
进入某个路由后,需要从服务器获取数据,我们可以通过两种方式来实现:
-
导航完成之后获取:先完成导航,然后在接下来的组件生命周期钩子中获取数据。在数据获取期间显示“加载中”之类的指示。
当你使用这种方式时,我们会马上导航和渲染组件,然后在组件的 created 钩子中获取数据。这让我们有机会在数据获取期间展示一个 loading 状态,还可以在不同视图间展示不同的 loading 状态。假设我们有一个 Post
组件,需要基于 $route.params.id
获取文章数据
<template>
<div class="post">
<div v-if="loading" class="loading">Loading...</div>
<div v-if="error" class="error">{{ error }}</div>
<div v-if="post" class="content">
<h2>{{ post.title }}</h2>
<p>{{ post.body }}</p>
</div>
</div>
</template>
export default {
data() {
return {
loading: false,
post: null,
error: null,
}
},
created() {
// watch 路由的参数,以便再次获取数据
this.$watch(
() => this.$route.params,
() => {
this.fetchData()
},
// 组件创建完后获取数据,
// 此时 data 已经被 observed 了
{ immediate: true }
)
},
methods: {
fetchData() {
this.error = this.post = null
this.loading = true
// replace `getPost` with your data fetching util / API wrapper
getPost(this.$route.params.id, (err, post) => {
this.loading = false
if (err) {
this.error = err.toString()
} else {
this.post = post
}
})
},
},
}
-
导航完成之前获取:导航完成前,在路由进入的守卫中获取数据,在数据获取成功后执行导航。
通过这种方式,我们在导航转入新的路由前获取数据。我们可以在接下来的组件的 beforeRouteEnter
守卫中获取数据,当数据获取成功后只调用 next
方法:
export default {
data() {
return {
post: null,
error: null,
}
},
beforeRouteEnter(to, from, next) {
getPost(to.params.id, (err, post) => {
next(vm => vm.setData(err, post))
})
},
// 路由改变前,组件就已经渲染完了
// 逻辑稍稍不同
async beforeRouteUpdate(to, from) {
this.post = null
try {
this.post = await getPost(to.params.id)
} catch (error) {
this.error = error.toString()
}
},
}