Vue快速入门路由补充——(十)

40 阅读6分钟

vue:vue-router导航守卫

全局导航守卫

  1. 全局前置守卫beforeEach:一般用于权限校验
  2. 全局解析守卫beforeResolve:是获取数据或执行任何其他操作(如果用户无法进入页面时你希望避免执行的操作)的理想位置。
  3. 全局后置钩子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 守卫 只在进入路由时触发,不会在 paramsquery 或 hash 改变时触发。例如,从 /users/2 进入到 /users/3 或者从 /users/2#info 进入到 /users/2#projects。它们只有在 从一个不同的 路由导航时,才会被触发。

组件独享导航守卫

  1. beforeRouteEnter
  2. beforeRouteUpdate
  3. 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)
    }
}

完整的导航解析流程

  1. 导航被触发。
  2. 在失活的组件里调用 beforeRouteLeave 守卫。
  3. 调用全局的 beforeEach 守卫。
  4. 在重用的组件里调用 beforeRouteUpdate 守卫 (2.2+)。
  5. 在路由配置里调用 beforeEnter
  6. 解析异步路由组件。
  7. 在被激活的组件里调用 beforeRouteEnter
  8. 调用全局的 beforeResolve 守卫 (2.5+)。
  9. 导航被确认。
  10. 调用全局的 afterEach 钩子。
  11. 触发 DOM 更新。
  12. 调用 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的问题