vue:vue-router导航守卫
全局导航守卫
- 全局前置守卫
beforeEach
:一般用于权限校验 - 全局解析守卫
beforeResolve
:是获取数据或执行任何其他操作(如果用户无法进入页面时你希望避免执行的操作)的理想位置。 - 全局后置钩子
afterEach
:它们对于分析、更改页面标题、声明页面等辅助功能以及许多其他事情都很有用
//引入VueRouter
import VueRouter from 'vue-router'
// 引入组件
import Home from '../pages/Home'
import Message from '../pages/Message'
//创建router实例对象,去管理一组一组的路由规则
//注册路由
const routes = [{
path: '/',
name: 'home',
component: () => import("../views/home/index.vue")
},
{
path: '/home',
name: 'home2',
component: () => import("../views/home/index.vue")
},
{
path: '/login',
name: 'login',
component: () => import("../views/login/index.vue")
},
{
path: '/car',
name: 'car',
component: () => import("../views/car/index.vue")
},
{
path: '/news',
name: 'news',
component: () => import("../views/news/index.vue"),
beforeEnter(to,from,next){
console.log("beforeEnter",1111)
next()
}
},
{
path: '/*',
name: 'err',
component: () => import("../views/err/index.vue")
}
]
const router = new VueRouter({
mode: "history",
routes
})
router.beforeEach(function(to, from, next) {
//to,from路由信息对象
// console.log("无论进入哪个路由(只要每匹配一次路由) 都要先调用这个函数", 11111111111)
// console.log(to, from)
if (to.path == "/car"||to.path=="/info") {
var islogin=window.localStorage.getItem("islogin")
if(islogin=="ok"){
next()
}else{
next("/login")
}
} else {
next() //去匹配路由然后加载组件
}
// next("/car")
})
//这个守卫 知道它什么时候触发 我没用过
router.beforeResolve(function(to,from,next){
console.log("路由匹配完毕",to,from)
next()//渲染组件
})
//操作window
router.afterEach(function(to,from){
console.log("组件渲染了")
window.scrollTo(0,0)
})
//路由全局守卫: 所有路由匹配都会经过这三个钩子:beforeEach beforeResolve afterEach
//guard
路由独享守卫
beforeEnter
const routes = [
{
path: '/users/:id',
component: UserDetails,
beforeEnter: (to, from) => {
// reject the navigation
return false
},
},
]
beforeEnter 守卫 只在进入路由时触发,不会在 params
、query
或 hash
改变时触发。例如,从 /users/2
进入到 /users/3
或者从 /users/2#info
进入到 /users/2#projects
。它们只有在 从一个不同的 路由导航时,才会被触发。
组件独享导航守卫
beforeRouteEnter
beforeRouteUpdate
beforeRouteLeave
const UserDetails = {
template: `...`,
beforeRouteEnter(to, from) {
// 在渲染该组件的对应路由被验证前调用
// 不能获取组件实例 `this` !
// 因为当守卫执行时,组件实例还没被创建!
},
beforeRouteUpdate(to, from) {
// 在当前路由改变,但是该组件被复用时调用
// 举例来说,对于一个带有动态参数的路径 `/users/:id`,在 `/users/1` 和 `/users/2` 之间跳转的时候,
// 由于会渲染同样的 `UserDetails` 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。
// 因为在这种情况发生的时候,组件已经挂载好了,导航守卫可以访问组件实例 `this`
},
beforeRouteLeave(to, from) {
// 在导航离开渲染该组件的对应路由时调用
// 与 `beforeRouteUpdate` 一样,它可以访问组件实例 `this`
},
}
beforeRouteEnter守卫不能访问this
,因为守卫在导航确认前被调用,因此即将登场的新组件还没被创建
不过,可以通过传一个回调函数给next来访问组件实例。在导航被确认的时候执行回调,并且把组件实例作为回到方法的参数
beforeRouteEnter(to,from,next){
next(vm=>{
//通过`vm`访问组件实例
})
}
注意beforeRouteEnter是支持给next传递回调的唯一守卫。对于beforeRouteUpdate和beforeRouteLeave来说,this已经可用了,所以不支持传递回调,因为没有必要
beforeRouteUpdate(to,from,next)=>{
this.name = to.params.name
next()
}
beforeRouteLeave这个离开守卫通常用来禁止用户还未保存修改的前突然离开。该导航可以通过next(false)来取消
beforeRouteLeave(to,from,next){
const answer = window.confirm('Do you really want to leave? you have unsaved changes!')
if(answer){
next()
}else{
next(false)
}
}
完整的导航解析流程
- 导航被触发。
- 在失活的组件里调用
beforeRouteLeave
守卫。 - 调用全局的
beforeEach
守卫。 - 在重用的组件里调用
beforeRouteUpdate
守卫 (2.2+)。 - 在路由配置里调用
beforeEnter
。 - 解析异步路由组件。
- 在被激活的组件里调用
beforeRouteEnter
。 - 调用全局的
beforeResolve
守卫 (2.5+)。 - 导航被确认。
- 调用全局的
afterEach
钩子。 - 触发
DOM
更新。 - 调用
beforeRouteEnter
守卫中传给next
的回调函数,创建好的组件实例会作为回调函数的参数传入。
组合式 API中的路由函数
import { useRouter, useRoute } from 'vue-router'
export default {
setup() {
const router = useRouter()
const route = useRoute()
function pushWithQuery() {
router.push({
name: 'search',
query: {
...route.query,
},
})
}
},
}
组合式 API中的导航守卫
onBeforeRouteLeave
onBeforeRouteUpdate
import { onBeforeRouteLeave, onBeforeRouteUpdate } from 'vue-router'
export default {
setup() {
// 与 beforeRouteLeave 相同,无法访问 `this`
onBeforeRouteLeave((to, from) => {
const answer = window.confirm(
'Do you really want to leave? you have unsaved changes!'
)
// 取消导航并停留在同一页面上
if (!answer) return false
})
const userData = ref()
// 与 beforeRouteLeave 相同,无法访问 `this`
onBeforeRouteUpdate(async (to, from) => {
//仅当 id 更改时才获取用户,例如仅 query 或 hash 值已更改
if (to.params.id !== from.params.id) {
userData.value = await fetchUser(to.params.id)
}
})
},
}
总结 全局导航 :
前置守卫:router.beforeEach ========>>> 权限的控制
解析守卫:router.beforeResolve
后置守卫: router.afterEach
路由独享 :beforeEnter
组件内守卫:
beforeRouteEnter
beforeRouteUpadte
beforeRouteLeave
history 模式下不同页面跳转传参
history 模式下不同页面跳转传参
使用router 的name属性
也就是params来传递参数
//跳转到Message页面 传参
this.$router.push({
name:"Message"
params:{
userId:'1101'
}
})
//在Message页面取参数
this.$route.params.userId
使用query来传递参数
//跳转到login页面 传参
this.$router.push({
path:'/login',
query:{
userId:'1101'
}
})
//在login页面取参
this.$route.query.useId
总结
params 传参必须要有name属性
query 传参必须要有path属性
params类似于ajax中post传参,不会在url中展示参数,但是query则类似get传参,会在url中展示参数
query传参,刷新页面不会丢失参数。但是params会丢参的。
params 和path不能共存 所以只能用name
params传参 需要在 路由配置 path /:id 这样就不会丢参
最重要的一点,params刷新会消失。。。query则不会,params参数只要在路由中声明了就不会消失。
在路由声明了,跟query又有什么区别呢,干嘛不直接query呢,params不会出现在地址栏,更加美观。
路由声明path里加上参数(冒号加参数名称)比如 /article/:articleId/:articleType 这样你通过params传递的articleId和articleType就会在路由路径里。
$router是路由对象,是一个只写的对象
$route是当前路由的信息对象,是一个只读的对象
hash模式与history模式的区别
在本地开发的时候,其实两种模式对开发影响不大,主要是在项目部署上线的时候,影响较大。
history 模式下:将url地址输入到浏览器的时候或者刷新页面的时候,此时的url相当于发送了一次get请求,这个请求,后台可能会找不到资源的,所以会404。
但是hash 模式下,不会带着#后面的参数,所以不会有什么问题(hash值不会包含在HTTP请求中,即hash值不会带给服务器)。
-
hash模式:
-
hash模式是通过改变锚点(#)来更新页面URL,并不会触发页面重新加载,我们可以通过window.onhashchange监听到hash的改变,从而处理路由。它的特点在于:hash 虽然出现在 URL 中,但不会被包括在 HTTP 请求中,对后端完全没有影响,因此改变 hash 不会重新加载页面
-
地址中永远带着#号,不美观
-
兼容性较好(能兼容到IE8)
-
-
history 模式
-
history模式是通过调用window.history对象上的一系列方法来实现页面的无刷新跳转。
-
地址干净美观
-
兼容性与hash模式相比略差(能兼容到IE10)
-
应用部署上线时,需要后端支持,解决刷新页面服务端404的问题
-