Vue-router入门

219 阅读8分钟

vue-router概述

Vue Router 是 Vue.js 官方的路由管理器。它和 Vue.js 的核心深度集成,可用于构建单页面应用(SPA),vue的单页面应用是基于路由和组件的,路由用于设定访问路径,并将路径和组件映射起来。与传统的页面应用相比可做到更新视图而不请求页面

路由搭建(基于vue cli4)

1. 创建组件

首先需要创建出需要用到的组件,这里创建的是home和about组件

<!-- src/views/home.vue-->
<template>
  <div class='home'>
    <h1>首页</h1>
  </div>
</template>

<script>
  //导出组件
  export default {
    components: {
      name:"home"
    }
  }
</script>
<!-- src/views/about.vue -->
<template>
  <div class='about'>
    <h2>关于页</h2>
  </div>
</template>

<script>
  //导出组件
  export default {
    components: {
      name:"about"
    }
  }
</script>

2.创建路由与映射路由

  • 要想在一个模块化工程中使用路由,必须要通过 Vue.use() 明确地安装路由功能
  • 在实现路由映射时组件有两种导入方式,使用懒加载的方式导入在项目打包后运行速度更快
  • 创建路由实例中的mode参数有Hash模式和History模式,使用默认的hash模式URL会前面会带有'#',想要更好看的URL可以使用history模式
  1. hash 模式使用 URL 的 hash 来模拟一个完整的 URL,当 URL 改变时,页面不会重新加载,改变 hash 不会重新加载页面;同时每一次改变#后的部分,都会在浏览器的访问历史中增加一个记录,使用”后退”按钮,就可以回到上一个位置,hash 模式的原理是 onhashchange 事件(监测hash值变化),可以在 window 对象上监听这个事件。
  2. history模式利用了html5 history interface 中新增的 pushState()replaceState()方法,这两个方法应用于浏览器记录栈,在当前已有的 back、forward、go 基础之上,它们提供了对历史记录修改的功能。当它们执行修改时虽会改变当前的 URL ,但浏览器不会立即向后端发送请求。
/*-------src/router/index.js--------*/
import Vue from 'vue'
import VueRouter from 'vue-router'
import home from '../views/home' //普通导入方式

Vue.use(VueRouter)

//在此实现路由映射
const routes = [{
    path:'',
    redirect: '/home' //redirect重定向实现默认页
  },
  {
    path: '/home',
    name: 'home',
    component: home
  },
  {
    path: '/about',
    name: 'about',
    component: () => import( '../views/about.vue') //懒加载导入方式
  }
]

//创建路由实例
const router = new VueRouter({
  mode: 'history',   //使用history模式
  base: process.env.BASE_URL,
  routes
})

//导出router
export default router

3. router-link与router-view

  • <router-link> 组件支持用户在具有路由功能的应用中 (点击) 导航。 通过 to 属性指定目标地址,默认渲染成带有正确链接的a标签,可以通过配置 tag 属性生成别的标签.。另外,当目标路由成功激活时,链接元素自动设置一个表示激活的 CSS 类名。 关于router-link的具体属性可查阅:router.vuejs.org/zh/api/#rou…
  • <router-view>组件是一个 functional 组件,渲染路径匹配到的视图组件。router-view 渲染的组件还可以内嵌自己的 router-view,根据嵌套路径,渲染嵌套组件。 关于router-view的具体属性可查阅:router.vuejs.org/zh/api/#rou…
<!--- src/App.vue --->
<template>
  <div id="app">
    <div id="nav">
      <router-link to="/home">Home</router-link> 
      <router-link to="/about">About</router-link>
    </div>
    <router-view/>
  </div>
</template>
/*--- src/main.js ---*/
import Vue from 'vue'
import App from './App.vue'
import router from './router' //导入router

Vue.config.productionTip = false

//创建vue实例
new Vue({
  router,
  render: h => h(App) 
}).$mount('#app')

4. 执行过程

  • vue-router首先会去查找<router-link>的路由映射
  • 然后根据路由映射找到匹配的组件
  • 最后将组件渲染到<router-view>标签

动态路由

此处以添加user页为例,user页面的URL地址将表现为/user/userName 实现步骤为创建user组件=>添加user路由映射=>App.vue页面定义user_id变量并进行渲染

<!-- src/views/user.vue -->
<template>
  <div class="user">
	<!--getUserId为计算属性-->
    <h1>{{ getUserId }}</h1> 
  </div>
</template>

<script>
export default {
  components: {
    name: "user",
  },
  computed: {
    getUserId() {
      //此处为route,表示当前活跃路由
      return this.$route.params.user_id;
    },
  },
};
</script>
/*-------src/router/index.js---------*/
import Vue from 'vue'
import VueRouter from 'vue-router'
import home from '../views/home'

Vue.use(VueRouter)

//实现路由映射
const routes = [{
    path: '',
    redirect: '/home'
  },
  {
    path: '/home',
    name: 'home',
    component: home
  },
  {
    path: '/about',
    name: 'about',
    component: () => import('../views/about')
  },
  //user路由映射
  {
    path: '/user/:user_id',
    name: 'user',
    component: () => import('../views/user') 
  }
]

//创建路由实例
const router = new VueRouter({
  mode: 'history',
  base: process.env.BASE_URL,
  routes
})

//导出router
export default router
<!-- src/App.vue -->
<template>
  <div id="app">
    <div id="nav">
      <router-link to="/home">首页</router-link>
      <router-link to="/about">关于</router-link>
      <router-link :to="'/user/' + user_id">用户</router-link>
      <!--这里使用了v-bind,动态绑定user_id-->
    </div>
    <router-view />
  </div>
</template>

<script>
export default {
  name: "App",
  data() {
    return {
      user_id: "xiehaopei",
    };
  },
};
</script>

嵌套路由

目前想在首页中再嵌套一个路由选择,可以在home页面通过路由渲染出message页面和news页面

<!-- src/views/home_message -->
<template>
  <div class="">
    <ul>
      <li>消息1</li>
      <li>消息2</li>
      <li>消息3</li>
      <li>消息4</li>
      <li>消息5</li>
    </ul>
  </div>
</template>

<script>
export default {
  components: {
    name: "message"
  }
};
</script>
<!-- src/views/home_news.vue -->
<template>
  <div class="">
    <ul>
      <li>新闻1</li>
      <li>新闻2</li>
      <li>新闻3</li>
      <li>新闻4</li>
      <li>新闻5</li>
    </ul>
  </div>
</template>

<script>
export default {
  components: {
    name: "news"
  }
};
</script>
<!-- src/views/home.vue -->
<template>
  <div class="home">
    <h1>
      首页
    </h1>
    <router-link to="/home/news">新闻</router-link>
    <router-link to="/home/message">消息</router-link>
    <router-view></router-view>
  </div>
  
</template>

<script>
export default {
  name: "home",
};
</script>
/*-------src/router/index.js---------*/
/*---routes片段---*/
{
    path: '/home',
    name: 'home',
    component: home,
    children: [
      {
        path: "",
        redirect: "news"
      },
      {
        path: "news",
        component: ()=>import('../views/home_news')
      },
      {
        path: "message",
        component: () => import('../views/home_message')
      }
    ]
  }

这样就可以实现在一个页面中通过路由调用不同组件的效果了

路由对象

$route

$route是“路由信息对象”,包括 path,params,hash,query,fullPath,matched,name 等路由信息参数。

  • $route.path 字符串,等于当前路由对象的路径,会被解析为绝对路径,如 "/home/news" 。
  • $route.params 对象,包含路由中的动态片段和全匹配片段的键值对
  • route.query 
对象,包含路由中查询参数的键值对。例如,对于`/home/news/detail/01?favorite=yes` ,会得到 `route.query.favorite == 'yes'` 。
  • $route.router 路由规则所属的路由器(以及其所属的组件)。
  • $route.matched 数组,包含当前匹配的路径中所包含的所有片段所对应的配置参数对象。
  • $route.name 当前路径的名字,如果没有使用具名路径,则名字为空。

$router

$router 是“路由实例对象",即使用 new VueRouter创建的实例,包括了路由的跳转方法,钩子函数等。 跳转方法示例:

  • $router.go(-1) 跳转到上一次浏览的页面
  • $router.replace('url') 跳转到指定地址
  • $router.push('/home') 通过push进行跳转

$router.push$router.replace的区别:

  1. 使用push方法的跳转会向 history 栈添加一个新的记录,当我们点击浏览器的返回按钮时可以看到之前的页面。
  2. 使用replace方法不会向 history 添加新记录,而是替换掉当前的 history 记录,即当replace跳转到的网页后,‘后退’按钮不能查看之前的页面。

导航守卫

守卫方法参数

每个守卫方法接收三个参数:

  • to: Route: 即将要进入的目标 路由对象
  • from: Route: 当前导航正要离开的路由
  • next: Function: 一定要调用该方法来 resolve 这个钩子。执行效果依赖 next 方法的调用参数,next方法参数如下:
  • next()方法会进行管道中的下一个钩子,如果全部钩子执行完了,则导航的状态就是 confirmed (确认的)。
  • next(false): 中断当前的导航。如果浏览器的 URL 改变了 (可能是用户手动或者浏览器后退按钮),那么 URL 地址会重置到 from 路由对应的地址。
  • next('/') 或者 next({ path: '/' }): 跳转到一个不同的地址。当前的导航被中断,然后进行一个新的导航。你可以向 next 传递任意位置对象,且允许设置诸如 replace: true、name: 'home' 之类的选项以及任何用在 router-link 的 to prop 或 router.push 中的选项。
  • next(error): (vue router2.4.0+) 如果传入 next 的参数是一个 Error 实例,则导航会被终止且该错误会被传递给 router.onError() 注册过的回调。 确保要调用 next 方法,否则钩子就不会被 resolved。

全局前置守卫

可以使用 router.beforeEach注册一个全局前置守卫,当一个导航触发时,全局前置守卫按照创建顺序调用。守卫是异步解析执行,此时导航在所有守卫 resolve 完之前一直处于 等待中

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

全局后置钩子

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

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

路由独享守卫

可以在路由配置上直接定义 beforeEnter守卫,这些守卫与全局前置守卫的方法参数是一样的

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

组件内守卫

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

导航流程

  1. 导航被触发。
  2. 在失活的组件里调用离开守卫。
  3. 调用全局的beforeEach守卫。
  4. 在重用的组件里调用 beforeRouteUpdate 守卫。
  5. 在路由配置里调用beforeEnter
  6. 解析异步路由组件。
  7. 在被激活的组件里调用 beforeRouteEnter
  8. 调用全局的beforeResolve守卫 (2.5+)。
  9. 导航被确认。
  10. 调用全局的afterEach钩子。
  11. 触发 DOM 更新。
  12. 用创建好的实例调用 beforeRouteEnter 守卫中传给next的回调函数。

设置404页面

当用户输错页面时会我们希望能够显示出404页面,通过以下配置可以得到一个自定义的404页面

/*-------src/router/index.js--------*/
//path:'*'表现为输入地址不匹配时,自动显示出Error.vue的文件内容
const routes = [{
	   path:'*',
	   component: () => import('../views/Error.vue') 
	}]
<!-- src/views/Error.vue-->
<template>
  <div class='error'>
    <h1>404</h1>
  </div>
</template>

<script>
  //导出组件
  export default {
    components: {
      name:"Error"
    }
  }
</script>

<style>
</style>