vue-router

官方文档

路由模式

  1. hash路由http://www.abc.com/#/hello
    • 使用window.onHashChange来监听hash值的改变,一旦发生变化就找出此hash值所匹配的组件,进而将组件渲染到页面中。
    • url的hash发生变化时,不会向后端发送请求。
      实现原理
      1)vue-router会通过监听window对象的hashchange事件来捕获URL的变化。
      2)当URL的hash值发生变化时,vue-router会根据新的hash值找到对应的路由配置,并将对应的组件渲染到页面中的标签中。
  2. history路由http://www.abc.com/hello
    • 通过window.onpopstate来监听路由变化,进而匹配不同的组件来渲染出来。
    • 当 URL 发生变化时,浏览器会向服务器发送请求,服务器需要配置相应的路由规则,以确保在刷新页面或直接访问 URL 时能正确响应路由。
      实现原理
      1)vue-router会通过history.pushState()方法或history.replaceState()方法来改变URL的路径部分,而不会触发页面的刷新。包括forward()、back()、go()三个方法,对应浏览器的前进,后退,跳转操作
      2)当URL的路径发生变化时,浏览器会向服务器发送请求,服务器需要配置相应的路由规则来返回对应的页面。
      3)当服务器返回对应的页面后,vue-router会将返回的页面渲染到页面中的标签中。
      history关于404的处理:首先服务器需要支持配置路由,对于所有路由都会返回一个html文件,需要在vue应用里覆盖所有路由的情况,再给一个404页面。(可以通过node或者nginx服务器配置)
  3. 优缺点分析
    hash配置简单,但是路由不好看,history路由好看,但是配置复杂,需要服务端配置。

路由跳转

  1. router-link
  2. this.$router.push():跳转到不同的url,但这个方法会向history栈添加一个记录,点击后退会返回到上一个页面。
  3. this.$router.replace():同样是跳转到指定的url,但是这个方法不会向history里面添加新的记录,点击返回,会跳转到上上一个页面。上一个记录是不存在的。
  4. this.$router.go(n):相对于当前页面向前或向后跳转多少个页面,类似 window.history.go(n),n可为正数可为负数。正数返回上一个页面。
  5. this.router.forward() 前进一步
  6. this.router.back() 回退一步

导航守卫

  1. 全局前置守卫beforeEach((to, from, next) => {}):按照创建顺序调用。守卫是异步解析执行,此时导航在所有守卫 resolve 完之前一直处于等待中,如果不调用next,那么钩子不会被resolve

  2. 全局解析守卫beforeResolve((to, from) => {}):获取数据或执行任何其他操作最优位置

  3. 全局后置钩子afterEach(to, from)

  4. 路由独享的守卫beforeEnter(to, from):从一个不同的 路由导航时,才会被触发,只有路由变化才会调用,params、hash、query变化时不会调用

  5. 组件内的守卫
    beforeRouteEnter(to, from)

    • 在渲染该组件的对应路由被验证前调用
    • 不能获取组件实例 this (因为当守卫执行时,组件实例还没被创建)
    • 可以通过传一个回调给 next 来访问组件实例。在导航被确认的时候执行回调,并且把组件实例作为回调方法的参数

    beforeRouteUpdate(to, from)

    • 在当前路由改变,但是该组件被复用时调用,可以访问组件实例this

    beforeRouteLeave(to, from)

    • 在导航离开渲染该组件的对应路由时调用,可以访问组件实例this

路由解析流程

  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 的回调函数,创建好的组
  13. 实例会作为回调函数的参数传入。

数据获取方式

  • 导航完成之后获取:先完成导航,然后在接下来的组件生命周期钩子中获取数据。在数据获取期间显示“加载中”之类的指示。watch 路由的参数,以便再次获取数据
created() {
  // watch 路由的参数,以便再次获取数据
  this.$watch(
    () => this.$route.params,
    () => {
      // 获取数据
      this.fetchData() 
    },
    // 组件创建完后获取数据,
    // 此时 data 已经被 observed 了
    { immediate: true }
  )
},
  • 导航完成之前获取:导航完成前,在路由进入的守卫中获取数据,在数据获取成功后执行导航。我们可以在接下来的组件的 beforeRouteEnter 守卫中获取数据,当数据获取成功后只调用 next 方法
beforeRouteEnter(to, from, next) {
  getPost(to.params.id, (err, post) => {
    next(vm => vm.setData(err, post)) // setData获取数据
  })
},
// 路由改变前,组件就已经渲染完了
// 逻辑稍稍不同
async beforeRouteUpdate(to, from) {
  this.post = null
  try {
    this.post = await getPost(to.params.id)
  } catch (error) {
    this.error = error.toString()
  }
},

路由懒加载

也称为动态加载路由,当打包构建应用时,JavaScript 包会变得非常大,影响页面加载。如果我们能把不同路由对应的组件分割成不同的代码块,然后当路由被访问的时候才加载对应组件,这样就会更加高效,提高应用的初始加载速度。

vue-router动态导入:

routes: [
  { path: '/users/:id', component: () => import('./views/UserDetails.vue') },
],

component接收一个返回 Promise 组件的函数,Vue Router 只会在第一次进入页面时才会获取这个函数,然后使用缓存数据
三种方式实现:

  1. Vue异步组件
    component: resolve => require(['放入需要加载的路由地址'],resolve)
  2. ES6的 import()
import Vue from 'vue';
import Router from 'vue-router';
// 下面没有指定webpackChunkName,每个组件打包成一个js文件。
const Foo = () => import('../components/Foo')
// 指定了相同的webpackChunkName,会合并打包成一个js文件。
// const Foo = () => import(/* webpackChunkName: 'ImportFuncDemo' */ '../components/Foo')
// const Aoo = () => import(/* webpackChunkName: 'ImportFuncDemo' */ '../components/Aoo')
...
{path:'/Foo',name:'Foo',component:Foo},
  1. webpack的 require.ensure()
const Coo = resolve=>{
 require.ensure([],()=>{resolve(require('@/components/List'))})
}
...
{path:'/list',name:'List',component:Coo}
  • 第一个参数是数组,表明第二个参数里需要依赖的模块,这些会提前加载。
  • 第二个是回调函数,在这个回调函数里面require的文件会被单独打包成一个chunk,不会和主文件打包在一起,这样就生成了两个chunk,第一次加载时只加载主文件。
  • 第三个参数是错误回调。
  • 第四个参数是单独打包的chunk的文件名

保护路由

对于一些表单类型的页面,需要登录后使用,但用户直接访问需要保护的页面也是可以的,直到提交到后端的时候才会报错,交互不友好
通过Vue Router 提供的导航守卫来实现,通过设置路由导航钩子函数的方式添加守卫函数,在里面判断用户的登录状态和权限,从而达到保护指定路由的目的

实现路由

  • hash
    <ul>
        <li><a href="#/home">首页</a></li>
        <li><a href="#/about">关于</a></li>
    </ul>
    <!-- 渲染对应的ui -->
    <div id="routerView"></div>

    <script>
        let routerView = document.getElementById('routerView');   // 获取插入html的dom结构
        window.addEventListener('load',onHashchange)
        window.addEventListener('hashchange', onHashchange)// 浏览器自带的监听哈希值改变的方法:hashchange    
        // 控制渲染对应的 UI 
        function onHashchange() {
            // console.log(location.hash);
            switch (location.hash) { //  location.hash为哈希值
                case '#/home': 
                  routerView.innerHTML = 'Home'
                  return
                case '#/about':
                  routerView.innerHTML = 'About'
                  return
                default:
                  return
            }
        }
        routerView.innerHTML = 'Home'
    </script>
  • history
  <ul>
    <li><a href="/home">首页</a></li>
    <li><a href="/about">关于</a></li>
  </ul>
  <!-- 渲染对应的UI -->
  <div id="routerView"></div>

  <script>
    let routerView = document.getElementById('routerView')
    window.addEventListener('DOMContentLoaded', onLoad)
    // window.addEventListener('popstate', onPopState)  // 浏览器的前进后退能匹配
   
    function onLoad() {
      onPopState()
      let links = document.querySelectorAll('li a[href]')
      // 拦截a标签的默认跳转行为
      links.forEach(a => {
        a.addEventListener('click', (e) => {
          e.preventDefault() // 阻止a标签的href行为
          
          history.pushState(null, '', a.getAttribute('href'))  // 跳转
          onPopState()
        })
      })
    }
    function onPopState() {
      // console.log(location.pathname);
      switch (location.pathname) {
        case '/home':
          routerView.innerHTML = '<h2>home page</h2>'
          return
        case '/about':
          routerView.innerHTML = '<h2>about page</h2>'
          return
        default:
          return
      }
    }
  </script>
  • 26
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值