Vue路由宇宙大全

参考文章链接
https://segmentfault.com/a/1190000011519350
https://www.cnblogs.com/anjx/p/11242387.html

vue的路由模式,分为三种模式:

1.Hash模式:使用URL的hash值来作为路由,支持所有浏览器。
2.History模式:以HTML5 History API 和服务器配置。
3.Abstract模式:支持所有js运行模式。如果发现没有浏览器的API,路由会强制进入这个模式。

两种模式的区别

1.hash模式——即地址栏URL中的#符号。比如http://www.abc.com/#/hello
特点在于:hash虽然出现URL中,但不会被包含在HTTP请求中,对后端完全没影响,因此改变hash不会重新加载页面。
hash模式下,仅hash符号之前的内容会被包含在请求中,因此对于后端,即使没有做到对路由的全覆盖,也不会返回错误。
hash模式背后的原理是onhashchange事件,可以在window对象上监听这个事件:
window.onhashchange = function (event) {
let hash = location.hash.slice(1);
document.body.style.color = hash;
}
因为hash发生变化的url都会被浏览器记录下来,从而你会发现浏览器的前进后退都可以用了
2.history模式——利用了H5 History Interface中新增的pushState()和replaceState()方法。这两方法应用于浏览器的历史记录栈,在当前已有的back、forward、go的基础上,提供了对历史记录进行修改的功能。
history模式下,前端的url必须和实际向后端发起请求的url一致。如www.abc.com/detail/id。如果后端缺少对/detail/id的路由处理,将返回404错误。

Vue-router 报NavigationDuplicated的解决方案

因为Vue-router在3.1之后把$router.push()方法改为了Promise。所以假如没有回调函数,错误信息就会交给全局的路由错误处理,因此会报错:[NavigationDuplicated {_name: "NavigationDuplicated", name: "NavigationDuplicated"}]
解决方法是重新改写VueRouter的push和replace方法,添加回调处理错误

import VueRouter from 'vue-router'
const VueRouterPush = VueRouter.prototype.push
VueRouter.prototype.push = function push(location) {
  return VueRouterPush.call(this, location).catch(err => err)
}
const VueRouterReplace = VueRouter.prototype.replace
VueRouter.prototype.replace = function replace(location) {
  return VueRouterReplace.call(this, location).catch(err => err)
}
Vue.use(VueRouter)

路由组件的按需加载

vue项目实现按需加载的3种方式
1.vue异步组件
2.es提案的import()
3.webpack的require.ensure()

1.vue异步组件技术

vue-router配置路由,使用vue的异步组件技术,可以实现按需加载。
但是,这种情况下一个组件生产一个js文件。

 {
            path: '/promisedemo',
            name: 'PromiseDemo',
            component: resolve =>     require(['../components/PromiseDemo'], resolve)
}
2.es提案的import()
  • 推荐使用这种方式(需要webpack > 2.4)
  • webpack官方文档:webpack中使用import()
// 下面2行代码,没有指定webpackChunkName,每个组件打包成一个js文件。
const ImportFuncDemo1 = () => import('../components/ImportFuncDemo1')
const ImportFuncDemo2 = () => import('../components/ImportFuncDemo2')

// 下面2行代码,指定了相同的webpackChunkName,会合并打包成一个js文件。
// const ImportFuncDemo = () => import(/* webpackChunkName: 'ImportFuncDemo' */ '../components/ImportFuncDemo')
// const ImportFuncDemo2 = () => import(/* webpackChunkName: 'ImportFuncDemo' */ '../components/ImportFuncDemo2')
3.webpack提供的require.ensure()

vue-router配置路由,使用webpack的require.ensure技术,也可以实现按需加载。

 {
            path: '/promisedemo',
            name: 'PromiseDemo',
            component: resolve => require.ensure([], () => resolve(require('../components/PromiseDemo')), 'demo')
        },
        {
            path: '/hello',
            name: 'Hello',
            // component: Hello
            component: resolve => require.ensure([], () => resolve(require('../components/Hello')), 'demo')
        }

路由守卫

vue-router全局守卫:

1.router.beforeEach 全局前置守卫 进入路由之前
2.router.beforeResolve 全局解析守卫(2.5.0+) 在beforeRouteEnter调用之后调用
3.router.afterEach 全局后置钩子 进入路由之后
导航钩子有3个参数:
1、to:即将要进入的目标路由对象;
2、from:当前导航即将要离开的路由对象;
3、next :调用该方法后,才能进入下一个钩子函数(afterEach)。

    next()//直接进to 所指路由
    next(false) //中断当前路由
    next('route') //跳转指定路由
    next('error') //跳转错误路由
router.beforeEach((to, from, next) => {
  if (from) {
    document.title = to.meta.title;
  } else {
    document.title = "创量广告投放平台";
  }
  next();
});
路由独享守卫

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

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

1.beforeRouteEnter 进入路由前
2.beforeRouteUpdate (2.2) 路由复用同一个组件时
3.beforeRouteLeave 离开当前路由时

beforeRouteEnter (to, from, next) {
    // 在路由独享守卫后调用 不!能!获取组件实例 `this`,组件实例还没被创建
  },
  beforeRouteUpdate (to, from, next) {
    // 在当前路由改变,但是该组件被复用时调用 可以访问组件实例 `this`
    // 举例来说,对于一个带有动态参数的路径 /foo/:id,在 /foo/1 和 /foo/2 之间跳转的时候,
    // 由于会渲染同样的 Foo 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。
  },
  beforeRouteLeave (to, from, next) {
    // 导航离开该组件的对应路由时调用,可以访问组件实例 `this`
  }
beforeRouteEnter访问this

因为钩子在组件实例还没被创建的时候调用,所以不能获取组件实例 this,可以通过传一个回调给next来访问组件实例 。
但是回调的执行时机在mounted后面,所以在我看来这里对this的访问意义不太大,可以放在created或者mounted里面。

beforeRouteEnter (to, from, next) {
    console.log('在路由独享守卫后调用');
      next(vm => {
        // 通过 `vm` 访问组件实例`this` 执行回调的时机在mounted后面,
      })
    }
beforeRouteLeave

导航离开该组件的对应路由时调用,我们用它来禁止用户离开,比如还未保存草稿,或者在用户离开前,将setInterval销毁,防止离开之后,定时器还在调用。

beforeRouteLeave (to, from , next) {
      if (文章保存) {
        next(); // 允许离开或者可以跳到别的路由 上面讲过了
      } else {
        next(false); // 取消离开
      }
    }

完整的路由导航解析流程(不包括其他生命周期):

1.触发进入其他路由。
2.调用要离开路由的组件守卫beforeRouteLeave
3.调用局前置守卫:beforeEach
4.在重用的组件里调用 beforeRouteUpdate
5.调用路由独享守卫 beforeEnter。
6.解析异步路由组件。
7.在将要进入的路由组件中调用beforeRouteEnter
8.调用全局解析守卫 beforeResolve
9.导航被确认。
10.调用全局后置钩子的 afterEach 钩子。
11.触发DOM更新(mounted)。
12.执行beforeRouteEnter 守卫中传给 next 的回调函数

1:导航守卫的执行顺序是怎么样的?

beforeRouteLeave < beforeEach < beforeRouteUpdate < beforeEnter < beforeRouteEnter < beforeResolve < afterEach

2:导航守卫中的next的用处?

next的作用,使导航守卫队列的继续向下迭代

3:为什么afterEach守卫没有next?

afterEach根本不在导航守卫队列内,没有迭代的next

4:beforeEach是否可以叠加?

beforeEach是可以叠加的,所有的全局前置守卫按顺序存放在beforeHooks的数组里面,

5:路由跳转经历了哪几部分?

路由跳转的核心方法是transitionTo,在跳转过程中经历了一次confirmTransition,

路由跳转

1. router-link
2. this.$router.push() (函数里面调用)
3. this.$router.replace() (用法同push)
4. this.$router.go(n)

一、不带参

1.1 router-link

  //name,path都行, 建议用name 

注意:router-link中链接如果是'/'开始就是从根路由开始,如果开始不带'/',则从当前路由开始。

1.2 this.$router.push()

this.$router.push('/home') 
this.$router.push({name:'home'}) 
this.$router.push({path:'/home'})

1.3 this.$router.replace() (用法同push)

二、带参

2.1 router-link


params传参数 (类似post)
路由配置 path: "/home/:id" 或者 path: "/home:id"
不配置path ,第一次可请求,刷新页面id会消失
配置path,刷新页面id会保留
html 取参 $route.params.id
script 取参this.$route.params.id


query传参数 (类似get,url后面会显示参数)
路由可不配置
html 取参 $route.query.id
script 取参 this.$route.query.id

2.2 this.$router.push

query传参
this.$router.push({
  name:'home',
  query: {id:'1'}
}) 

this.$router.push({
  path:'/home',
  query: {id:'1'}
}) 

this.$router.push("baidu.com?tab=2");

路由可不配置
html 取参 $route.query.id
script 取参 this.$route.query.id

params传参
this.$router.push({
  name:'home',
  params: {id:'1'}
})

只能用 name
路由配置 path: "/home/:id" 或者 path: "/home:id"
不配置path ,第一次可请求,刷新页面id会消失
配置path,刷新页面id会保留
html 取参 $route.params.id
script 取参 this.$route.params.id

2.3 this.$router.replace() (用法同push)

2.4 this.$router.go(n)
向前或者向后跳转n个页面,n可为正整数或负整数

区别:
this.$router.push 跳转到指定url路径,并想history栈中添加一个记录,点击后退会返回到上一个页面

this.$router.replace 跳转到指定url路径,但是history栈中不会有记录,点击返回会跳转到上上个页面 (就是直接替换了当前页面)

this.$router.go(n) 向前或者向后跳转n个页面,n可为正整数或负整数

你可能感兴趣的:(Vue路由宇宙大全)