路由守卫的核心作用是在路由跳转过程中执行特定的逻辑(如权限校验、数据预取)

路由 链接到标题

​ 一个路由(route)就是一组映射关系(key - value),多个路由需要路由器(router)进行管理

​ key是路径,value是组件

​ 安装vue-router,命令:npm i vue-router

const router = new VueRouter({
	routes:[
		{
			path:'/about',
			component:About
		},
		{
			path:'/home',
			component:Home
		}
	]
})

//暴露router
export default router

​ 路由组件通常存放在pages文件夹,一般组件通常存放在components文件夹

​ 通过切换,“隐藏”了的路由组件,默认是被销毁掉的,需要的时候再去挂载

​ 每个组件都有自己的$route属性,里面存储着自己的路由信息

标签实现路由的切换 指定组件的呈现位置

<router-link class="list-group-item" active-class="active" to="/about">About</router-link>
<router-link class="list-group-item" active-class="active" to="/home">Home</router-link>


<div class="panel">
  <div class="panel-body">
                <!-- 指定组件的呈现位置 -->
    <router-view></router-view>
  </div>
</div>

默认模式:

<!-- 点击后浏览器历史记录新增一条可通过后退回到上一页 -->
<router-link to="/detail">默认跳转</router-link>
<!-- 点击后替换当前历史记录无法通过后退回到上一页 -->
<router-link to="/detail" replace>replace 跳转</router-link>

多级路由 链接到标题

routes:[
	{
		path:'/about',
		component:About,
	},
	{
		path:'/home',
		component:Home,
		children:[ //通过children配置子级路由
			{
				path:'news', //此处一定不要写:/news
				component:News
			},
			{
				path:'message',//此处一定不要写:/message
				component:Message
			}
		]
	}
]

//跳转(要写完整路径)
<router-link to="/home/news">News</router-link>

路由传参—query参数 链接到标题

​ 两种方法:

​ 第一种,to变成 :to , 然后参数写在 ? 后面 。 a=${ data.x } 或者传 常量

<router-link :to="`/home/message/detail?id=${m.id}&title=${m.title}`">{{m.title}}</router-link>
<router-link :to="/home/message/detail?id=666&title=你好">跳转</router-link>

​ 第二种,to的对象写法 , 写 pathquery

<router-link 
	:to="{
		path:'/home/message/detail',
		query:{
		   id:666,
           title:'你好'
		}
	}"
>跳转</router-link>

路由传参—params参数 链接到标题

这个第一步需要先配置路由,使用占位符来接收参数

{
	path:'/home',
	component:Home,
	children:[
		{
			path:'news',
			component:News
		},
		{
			component:Message,
			children:[
				{
					name:'xiangqing',
					path:'detail/:id/:title', //使用占位符声明接收params参数
					component:Detail
				}
			]
		}
	]
}

​ 同样也有两种方法发送:

​ 第一种, 第一种,to变成 :to ,这个不需要❓ a=${ data.x } 或者传 常量

<router-link :to="/home/message/detail/666/你好">跳转</router-link>
<router-link :to="`/home/message/detail/${m.id}/${m.title}`">{{m.title}}</router-link>

<!-- 跳转并携带params参数to的对象写法 这里千万不能有path -->

<router-link 
	:to="{
		name:'xiangqing',
		params:{
		   id:666,
            title:'你好'
		}
	}"
>跳转</router-link>

路由接收参数 — 两个方法都一样 链接到标题

$route.query.id
$route.query.title
image-20260313215758075

命名路由–用于简化路由跳转 链接到标题

①给路由命名

{
	path:'/demo',
	component:Demo,
	children:[
		{
			path:'test',
			component:Test,
			children:[
				{
                    name:'hello' //给路由命名
					path:'welcome',
					component:Hello,
				}
			]
		}
	]
}

②简化跳转

<!--简化前需要写完整的路径 -->
<router-link to="/demo/test/welcome">跳转</router-link>

<!--简化后直接通过名字跳转 -->
<router-link :to="{name:'hello'}">跳转</router-link>

<!--简化写法配合传递参数 -->
<router-link 
	:to="{
		name:'hello',
		query:{
		   id:666,
            title:'你好'
		}
	}"
>跳转</router-link>

路由的props配置—方便收到参数 链接到标题

​ 方便体现在:

// 之前接收参数:  // Detail.vue
<template>
	<ul>
		<li>消息编号{{$route.params.id}}</li>
		<li>消息标题{{$route.params.title}}</li>
	</ul>
</template>

<script>
	export default {
		name:'Detail',
		mounted() {
			// console.log(this.$route)
		},
	}
</script>

// 使用propos配置 接收参数
<template>
	<ul>
		<li>消息编号{{id}}</li>
		<li>消息标题{{title}}</li>
	</ul>
</template>

<script>
	export default {
		name:'Detail',
		props:['id','title'],
	}
</script>

配置propos有三种方法:

写法类型 语法示例 优点 缺点 适用场景
对象写法 props: {a:1, b:'hello'} 1. 写法最简单;2. 传固定值非常方便 1. 只能传静态值,无法获取路由参数;2. 灵活性极低 仅需要给路由组件传固定常量的场景
布尔写法 props: true 1. 简洁,自动映射 params 参数;2. 组件解耦(不用写 $route 1. 仅支持 params 参数(不支持 query);2. 无法自定义参数名 / 新增额外参数 路由用 params 传参(如 /detail/:id),且参数名和组件 props 名一致的场景
函数写法 props($route) { return {id: $route.query.id} } 1. 支持 params/query 任意参数;2. 可自定义参数名、新增额外参数;3. 组件完全解耦 1. 写法比前两种稍复杂;2. 需要手动映射参数 绝大多数场景(尤其是用 query 传参、需要自定义参数、新增固定值的场景)
props($route){
    return {
        id:$route.query.id,
        title:$route.query.title,
        a:1,
        b:'hello'
    }
}

缓存路由组件 链接到标题

<keep-alive include="News"> 
    <router-view></router-view>
</keep-alive>

生命周期钩子:

  1. 作用:路由组件所独有的两个钩子,用于捕获路由组件的激活状态。
  2. 具体名字:
    1. activated路由组件被激活时触发。
    2. deactivated路由组件失活时触发。

不借助<router-link> 实现路由跳转,使用router的两个API

//$router的两个API,封装在一个函数里,通过调用函数触发路由跳转
function(){
    this.$router.xxx(??)
}
                     
// 操作有                    
this.$router.push({
	name:'xiangqing',
		params:{
			id:xxx,
			title:xxx
		}
})

this.$router.replace({
	name:'xiangqing',
		params:{
			id:xxx,
			title:xxx
		}
})
this.$router.forward() //前进
this.$router.back() //后退
this.$router.go() //可前进也可后退

优点:

​ 可结合任意事件触发(点击、双击、定时器、接口回调等); 前者只能点击

​ 跳转前可加复杂逻辑(表单验证、权限判断、参数加工)适配复杂业务场景;

支持路由守卫

缺点:

​ 不能用activate-class激活样式

​ 不能重复push到一个路由里面,需要加个判断,不然报错

全局路由守卫 链接到标题

全局守卫直接挂载在 router 实例上,对所有路由跳转生效

  • beforeEach(to, from, next)最常用。在路由跳转前触发,常用于登录状态校验。
  • beforeResolve(to, from, next) :在导航被确认之前,且组件内守卫和异步路由组件被解析之后调用。
  • afterEach(to, from) :在路由跳转完成后触发。注意: 它不接受 next 函数,也不会改变导航。


//全局前置守卫:初始化时执行、每次路由切换前执行
router.beforeEach((to,from,next)=>{
	console.log('beforeEach',to,from)
	if(to.meta.isAuth){ //判断当前路由是否需要进行权限控制
		if(localStorage.getItem('school') === 'atguigu'){ //权限控制的具体规则
			next() //放行
		}else{
			alert('暂无权限查看')
			// next({name:'guanyu'})
		}
	}else{
		next() //放行
	}
})

//全局后置守卫:初始化时执行、每次路由切换后执行
router.afterEach((to,from)=>{
	console.log('afterEach',to,from)
	if(to.meta.title){ 
		document.title = to.meta.title //修改网页的title
	}else{
		document.title = 'vue_test'
	}
})

路由独享守卫 链接到标题

如果你不想全局配置守卫的话,你可以为某些路由单独配置守卫:

    const router = new VueRouter({
      routes: [
        {
          path: '/foo',
          component: Foo,
          beforeEnter: (to, from, next) => { 
            // 参数用法什么的都一样,调用顺序在全局前置守卫后面,所以不会被全局守卫覆盖
            // ...
          }
        }
      ]
    })

组件内的路由守卫 链接到标题

直接定义在 .vue 组件内部,针对特定组件生效。

  • beforeRouteEnter:路由进入该组件前调用。此时拿不到组件实例 this,因为组件实例还没被创建。该钩子在全局守卫beforeEach之后,全局守卫afterEach之前调用。
  • beforeRouteUpdate:当前路由改变,且该组件被复用时调用(例如 /user/1 跳转到 /user/2)。
  • beforeRouteLeave:导航离开该组件时调用。常用于“离开前未保存”的选择提醒。
//进入守卫:通过路由规则,进入该组件时被调用
beforeRouteEnter (to, from, next) {
},
//离开守卫:通过路由规则,离开该组件时被调用
beforeRouteLeave (to, from, next) {
}

路由的hash和history模式的区别 链接到标题

Vue-Router有两种模式:hash模式history模式。默认的路由模式是hash模式。

1. hash模式 链接到标题

简介: hash模式是开发中默认的模式,它的URL带着一个#,例如:http://www.abc.com/#/vue,它的hash值就是 #/vue

特点:hash值会出现在URL里面,但是不会出现在HTTP请求中,对后端完全没有影响。所以改变hash值,不会重新加载页面。这种模式的浏览器支持度很好,低版本的IE浏览器也支持这种模式。hash路由被称为是前端路由,已经成为SPA(单页面应用)的标配。

原理: hash模式的主要原理就是onhashchange()事件

window.onhashchange = function(event){
    console.log(event.oldURL, event.newURL);
    let hash = location.hash.slice(1);
}

使用onhashchange()事件的好处就是,在页面的hash值发生变化时,无需向后端发起请求,window就可以监听事件的改变,并按规则加载相应的代码。除此之外,hash值变化对应的URL都会被浏览器记录下来,这样浏览器就能实现页面的前进和后退。虽然是没有请求后端服务器,但是页面的hash值和对应的URL关联起来了。

2. history模式 链接到标题

简介: history模式的URL中没有#,它使用的是传统的路由分发模式,即用户在输入一个URL时,服务器会接收这个请求,并解析这个URL,然后做出相应的逻辑处理。

特点: 当使用history模式时,URL就像这样:http://abc.com/user/id。相比hash模式更加好看。但是,history模式需要后台配置支持。如果后台没有正确配置,访问时会返回404。

API: history api可以分为两大部分,切换历史状态和修改历史状态:

  • 修改历史状态:包括了 HTML5 History Interface 中新增的 pushState()replaceState() 方法,这两个方法应用于浏览器的历史记录栈,提供了对历史记录进行修改的功能。只是当他们进行修改时,虽然修改了url,但浏览器不会立即向后端发送请求。如果要做到改变url但又不刷新页面的效果,就需要前端用上这两个API。
  • 切换历史状态: 包括 forward()back()go()三个方法,对应浏览器的前进,后退,跳转操作。

虽然history模式丢弃了丑陋的#。但是,它也有自己的缺点,就是在刷新页面的时候,如果没有相应的路由或资源,就会刷出404来。

如果想要切换到history模式,就要进行以下配置(后端也要进行配置):

const router = new VueRouter({
  mode: 'history',
  routes: [...]
})

3. 两种模式对比 链接到标题

调用 history.pushState() 相比于直接修改 hash,存在以下优势:

  • pushState() 设置的新 URL 可以是与当前 URL 同源的任意 URL;而 hash 只可修改 # 后面的部分,因此只能设置与当前 URL 同文档的 URL;
  • pushState() 设置的新 URL 可以与当前 URL 一模一样,这样也会把记录添加到栈中;而 hash 设置的新值必须与原来不一样才会触发动作将记录添加到栈中;
  • pushState() 通过 stateObject 参数可以添加任意类型的数据到记录中;而 hash 只可添加短字符串;
  • pushState() 可额外设置 title 属性供后续使用。
  • hash模式下,仅hash符号之前的url会被包含在请求中,后端如果没有做到对路由的全覆盖,也不会返回404错误;history模式下,前端的url必须和实际向后端发起请求的url一致,如果没有对用的路由处理,将返回404错误。

hash模式和history模式都有各自的优势和缺陷,还是要根据实际情况选择性的使用。

如何获取页面的hash变化 链接到标题

(1)监听$route的变化

// 监听,当路由发生变化的时候执行
watch: {
  $route: {
    handler: function(val, oldVal){
      console.log(val);
    },
    // 深度观察监听
    deep: true
  }
},

(2)window.location.hash读取#值

window.location.hash 的值可读可写,读取来判断状态是否改变,写入时可以在不重载网页的前提下,添加一条历史访问记录。

$route 和$router 的区别 链接到标题

  • $route 是“路由信息对象”,包括 path,params,hash,query,fullPath,matched,name 等路由信息参数
  • $router 是“路由实例”对象包括了路由的跳转方法,钩子函数等

Vue-router跳转和location.href有什么区别 链接到标题

  • 使用 location.href= /url 来跳转,简单方便,但是刷新了页面;
  • 使用 history.pushState( /url ) ,无刷新页面,静态跳转;
  • 引进 router ,然后使用 router.push( /url ) 来跳转,使用了 diff 算法,实现了按需加载,减少了 dom 的消耗。其实使用 router 跳转和使用 history.pushState() 没什么差别的,因为vue-router就是用了 history.pushState() ,尤其是在history模式下。

params和query的区别 链接到标题

用法:query要用path来引入,params要用name来引入,接收参数都是类似的,分别是 this.$route.query.namethis.$route.params.name

url地址显示:query更加类似于ajax中get传参,params则类似于post,说的再简单一点,前者在浏览器地址栏中显示参数,后者则不显示

注意:query刷新不会丢失query里面的数据 params刷新会丢失 params里面的数据。