vue开发干货Vue高级web前端

vue-router 常用知识点二

2019-02-19  本文已影响42人  我跟你蒋

目录

- 1.vue-router 动态路由匹配

- 2.router-link组件及其属性

- 3.vue-router路由的两种模式

- 4.vue-router有哪几种导航钩子( 导航守卫 )?

- 5.完整的导航解析流程

- 6.vue-router实现路由懒加载( 动态加载路由 )参考https://www.jianshu.com/p/a88a2ae4ebde


- 1. vue-router 动态路由匹配

我们经常需要把某种模式匹配到的所有路由,全都映射到同个组件。例如,我们有一个 User 组件,对于所有 ID 各不相同的用户,都要使用这个组件来渲染。那么,我们可以在 vue-router 的路由路径中使用“动态路径参数”(dynamic segment) 来达到这个效果:

const User = {
  template: '<div>User</div>'
}

const router = new VueRouter({
  routes: [
    // 动态路径参数 以冒号开头
    { path: '/user/:id', component: User }
  ]
})

现在呢,像 /user/foo/user/bar 都将映射到相同的路由。

一个“路径参数”使用冒号 : 标记。当匹配到一个路由时,参数值会被设置到 this.$route.params,可以在每个组件内使用。于是,我们可以更新 User 的模板,输出当前用户的 ID:

const User = {
  template: '<div>User {{ $route.params.id }}</div>'
}

你可以看看这个在线例子

你可以在一个路由中设置多段“路径参数”,对应的值都会设置到 $route.params 中。例如:

模式 匹配路径 $route.params
/user/:username /user/evan { username: 'evan' }
/user/:username/post/:post_id /user/evan/post/123 { username: 'evan', post_id: '123' }

除了 $route.params 外,$route 对象还提供了其它有用的信息,例如,$route.query (如果 URL 中有查询参数)、$route.hash 等等。你可以查看 API 文档 的详细说明。

- 2. router-link组件及其属性

支持用户在具有路由功能的应用中 (点击) 导航 通过 to 属性指定目标地址
一:router-link组件的props:

表示目标路由的链接。当被点击后,内部会立刻把 to 的值传到 router.push()

<router-link :to='/Home'>Home</router-link>
渲染结果:
<a href="Home">Home</a>
<router-link :to="{ path: 'register', query: { name: 'fjw' }}">router</router-link>
渲染结果:
<a href="/register?name=fjw">router</a>

指定<router-link>组件最终被渲染成什么标签;非必须;如果没有tag属性,router-link最终会被渲染成a标签。在上面的栗子中,渲染成了li标签。

<router-link :to='/Home' tag="li" >Home</router-link>
渲染结果:
<li>Home</li>
此时依旧会监听点击事件,触发导航

当点击时,会调用 router.replace() 而不是 router.push(),于是导航后不会留下 history 记录。

<router-link :to="{ path: '/abc'}" replace></router-link>

则在当前 (相对) 路径前添加基路径。/a 导航到一个相对路径 b,如果没有配置 append,则路径为 /b,如果配了,则为 /a/b

<router-link :to="{ path: 'relative/path'}" append></router-link>

"是否激活" 默认类名的依据是 inclusive match (全包含匹配)。

<!-- 这个链接只会在地址为 / 的时候被激活 -->
<router-link to="/" exact>

默认值: 'click' 声明可以用来触发导航的事件。可以是一个字符串或是一个包含字符串的数组。

默认值: "router-link-exact-active" 配置当链接被精确匹配的时候应该激活的 class。

- 3.vue-router路由的两种模式mode

url 的 hash 是以 # 开头,原本是用来作为锚点,从而定位到页面的特定区域。当 hash 改变时,页面不会因此刷新,浏览器也不会向服务器发送请求。
http://www.xxx.com/#/home
同时, hash 改变时,并会触发相应的 hashchange 事件。所以,hash 很适合被用来做前端路由。当 hash 路由发生了跳转,便会触发 hashchange 回调,回调里可以实现页面更新的操作,从而达到跳转页面的效果。
hash模式的工作原理是hashchange事件,可以在window监听hash的变化。我们在url后面随便添加一个#xx触发这个事件。

  window.onhashchange = function(event){
    console.log(event);
  }

image

可以看到里边有两个属性newURL和oldURL。可以通过模拟改变hsh的值,动态页面数据。

<div id="test" style="height: 500px;width: 500px;margin: 0 auto"></div>
<script>
  window.onhashchange = function(event){
    let hash = location.hash.slice(1);
    document.body.style.color = hash;
    document.getElementById('test').style.backgroundColor = hash
  }
</script>

image
尽管浏览器没有请求服务器,但是页面状态和url已经关联起来了,这就是所谓的前端路由,单页应用的标配。

HTML5 规范中提供了 history.pushState 和 history.replaceState 来进行路由控制。通过这两个方法,可以实现改变 url 且不向服务器发送请求。同时不会像 hash 有一个 # ,更加的美观。但是 History 路由需要服务器的支持,并且需将所有的路由重定向到根页面。

History 路由的改变不会去触发某个事件,所以我们需要去考虑如何触发路由更新后的回调。

有以下两种方式会改变 url:

第一个方式可以封装一个方法,在调用 pushState(replaceState)后再调用回调。

function push (url) {
 window.history.pushState({}, null, url);
 handleHref();
}
 
function handleHref () {
 console.log('render');
}

第二个方式,浏览器的前进与后退会触发 popstate 事件。

window.addEventListener('popstate', handleHref);
image

前进,后退,跳转操作方法:

  history.go(-3);//后退3次
  history.go(2);//前进2次
  history.go(0);//刷新当前页面
  history.back(); //后退
  history.forward(); //前进

https://router.vuejs.org/zh/guide/essentials/history-mode.html#%E5%90%8E%E7%AB%AF%E9%85%8D%E7%BD%AE%E4%BE%8B%E5%AD%90

这篇文章介绍的较为详细,讲到了实现原理https://juejin.im/post/5b330142e51d4558b10a9cc5

- 4.vue-router有哪几种导航钩子( 导航守卫 )?

vue-router 提供的导航守卫主要用来通过跳转或取消的方式守卫导航。
例如判断登录信息:没登录全部跳到登录页。判断必要操作是否进行没进行的话中断跳转。
参数或查询的改变并不会触发进入/离开的导航守卫。你可以通过观察 $route 对象来应对这些变化,或使用 beforeRouteUpdate 的组件内守卫。

分为三大类:全局守卫、路由守卫、组件守卫

[#]全局前置守卫

你可以使用 router.beforeEach 注册一个全局前置守卫:

const router = new VueRouter({ ... })

router.beforeEach((to, from, next) => {
  // ...
})

当一个导航触发时,全局前置守卫按照创建顺序调用。守卫是异步解析执行,此时导航在所有守卫 resolve 完之前一直处于 等待中。
每个守卫方法接收三个参数:

确保要调用 next 方法,否则钩子就不会被 resolved。

#全局解析守卫

在 2.5.0+ 你可以用 router.beforeResolve 注册一个全局守卫。这和 router.beforeEach 类似,区别是在导航被确认之前,同时在所有组件内守卫和异步路由组件被解析之后,解析守卫就被调用。

#全局后置钩子

你也可以注册全局后置钩子,然而和守卫不同的是,这些钩子不会接受 next 函数也不会改变导航本身:

router.afterEach((to, from) => {
  // ...
})

#路由独享的守卫

你可以在路由配置上直接定义 beforeEnter 守卫:

const router = new VueRouter({
  routes: [
    {
      path: '/foo',
      component: Foo,
      beforeEnter: (to, from, next) => {
        // ...
      }
    }
  ]
})

这些守卫与全局前置守卫的方法参数是一样的。

#组件内的守卫

最后,你可以在路由组件内直接定义以下路由导航守卫:

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

beforeRouteEnter 守卫 不能 访问 this,因为守卫在导航确认前被调用,因此即将登场的新组件还没被创建。

不过,你可以通过传一个回调给 next来访问组件实例。在导航被确认的时候执行回调,并且把组件实例作为回调方法的参数。

beforeRouteEnter (to, from, next) {
  next(vm => {
    // 通过 `vm` 访问组件实例
  })
}

注意 beforeRouteEnter 是支持给 next 传递回调的唯一守卫。对于 beforeRouteUpdatebeforeRouteLeave 来说,this 已经可用了,所以不支持传递回调,因为没有必要了。

beforeRouteUpdate (to, from, next) {
  // just use `this`
  this.name = to.params.name
  next()
}

这个离开守卫通常用来禁止用户在还未保存修改前突然离开。该导航可以通过 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. 在失活的组件里调用离开守卫。
  3. 调用全局的 beforeEach 守卫。
  4. 在重用的组件里调用 beforeRouteUpdate 守卫 (2.2+)。
  5. 在路由配置里调用 beforeEnter
  6. 解析异步路由组件。
  7. 在被激活的组件里调用 beforeRouteEnter
  8. 调用全局的 beforeResolve 守卫 (2.5+)。
  9. 导航被确认。
  10. 调用全局的 afterEach 钩子。
  11. 触发 DOM 更新。
  12. 用创建好的实例调用 beforeRouteEnter 守卫中传给 next 的回调函数。
图片描述
上一篇 下一篇

猜你喜欢

热点阅读