Skip to content

vue-router

vue-router 中常用的路由模式

hash hashchange

history

  • HTML5 History API( pushState、replaceState)
  • 这两个方法有个共同的特点:当调用他们修改浏览器历史记录栈后,虽然当前 URL 改变了,但浏览器不会刷新页面,这就为单页应用前端路由“更新视图但不重新请求页面”提供了基础

路由组件复用,导致路由参数

  • 用 key 阻止复用
js
<router-view :key="$route.fullPath" />
  • 通过 watch 监听路由参数再发请求
js
watch: { //通过watch来监听路由变化
  "$route": function(){
    this.getData(this.$route.params.xxx);
  }
}

失活组件的beforeRouterLeave => 全局的beforeEach => 重用组件的beforeRouterUpdate => 路由组件的beforeEnter => 解析异步路由组件=> 被激活组件的beforeRouterEnter => 全局的beforeResolve => 导航被确认 => 全局的afterEach => 触发Dom更新 => 调用beforeRouterEnter的next函数

路由钩子函数

  • 全局前置守卫: beforeEach

  • 全局后置钩子: afterEach

  • 路由独享钩子: beforeEnter

js
const router = new VueRouter({
  routes: [
    {
      path: '/home',
      component: Home,
      beforeEnter: (to, from, next) = {
        // to do somethings
        // 参数与全局守卫参数一样
    	}
    }
  ]
})
  • 组件内钩子: beforeRouteEnter
js
const Home = {
  template: `<div></div>`,
  beforeRouteEnter(to, from, next){
    // 在渲染该组件的对应路由被 confirm 前调用
    // 不能获取组件实例 ‘this’,因为当守卫执行前,组件实例还没被创建
  },
  beforeRouteUpdate(to, from, next){
    // 在当前路由改变,但是该组件被复用时调用
    // 例:对于一个动态参数的路径 /home/:id,在/home/1 和 /home/2 之间跳转的时候
    // 由于会渲染同样的 Home 组件,因此组件实例会被复用,而这个钩子就会在这个情况下被调用。
    // 可以访问组件实例 'this'
  },
  beforeRouteLeave(to, from, next){
    // 导航离开该组件的对应路由时调用
    // 可以访问组件实例 'this'
  }
}

切换路由后,新页面要滚动到顶部或保持原先的滚动位置

js
const router = new Router({
    mode: 'history',
    base: process.env.BASE_URL,
    routes,
    scrollBehavior(to, from, savedPosition) {
      if (savedPosition) {
          return savedPosition;
      } else {
          return { x: 0, y: 0 };
      }
    }
});

什么是命名视图

components 配置 (记得加上s)。

js
function load(component) {
    return resolve => require([`views/${component}`], resolve);
}
const routes=[
  {
    path: '/',
    redirect: '/home',
    name: 'layout',
    component: load('layout'),
    children: [
      {
        path: '/home',
        name: 'home',
        components: {
          default: load('main'),
          header: load('header'),
          sider: load('sider')
        },
        meta: {
          title: '首页'
        },
      },
    ]
  }
]
vue
<template>
  <div>
    <div>
        //...头部导航
        <router-view name='header'></router-view>
    <div>
        //...侧边栏导航
        <router-view name='sider'></router-view>
    </div>
    <div>
        //...主内容
        <router-view/>
    </div>
  </div>
</template

路由组件和路由为什么解耦

因为在组件中使用 $route 会使之与其对应路由形成高度耦合,从而使组件只能在某些特定的 URL 上使用,限制了其灵活性

使用 props 来解耦

props为true,route.params将会被设置为组件属性。 props为对象,则按原样设置为组件属性。 props为函数,http://localhost:8036/home?id=123,会把123传给组件Home的props的id

js
const Home = {
    props: ['id'],
    template: '<div>User {{ id }}</div>'
}
const router = new VueRouter({
  routes: [
    { path: '/home/:id', component: Home, props: true},
    // 对于包含命名视图的路由,你必须分别为每个命名视图添加 `props` 选项:
    {
        path: '/home/:id',
        components: { default: Home, sidebar: Sidebar },
        props: { default: true, sidebar: false }
    }
    { path: '/home', component: Home, props: {id:123} },
    { path: '/home', component: Home, props: (route) => ({ id: route.query.id }) },
  ]
})

如果vue-router使用history模式,部署时要注意什么?

要注意404的问题,因为在history模式下, 在Ngnix中将所有请求都转发到index.html上就可以了。

router-view

matched是一个由record类型元素组成的,其index 由 0 到最后, 因此是父--->子。 而routerView 的 render 函数通过定义一个 depth 参数,来判断当前嵌套的路由是位于 matched 函数的哪个index,然后取出对应的record对象,渲染器对应的组件。

在 MIT 许可下发布