1. 注册路由器插件
    在 ./router/index.js 中,引入 VueRouter 插件并用 Vue.use() 注册。
  2. 创建路由对象
    定义路由规则数组,并传入创建的 VueRouter 实例对象,导出对象。
  1. import Vue from 'vue'
  2. import VueRouter from 'vue-router'
  3. import Index from '../views/Index.vue'
  4. // 1. 注册路由插件
  5. // Vue.use 是用来注册插件,他会调用传入对象的 install 方法
  6. Vue.use(VueRouter)
  7. // 路由规则
  8. const routes = [
  9. {
  10. path: '/',
  11. name: 'Index',
  12. component: Index
  13. },
  14. {
  15. path: '/blog',
  16. name: 'Blog',
  17. // route level code-splitting
  18. // this generates a separate chunk (about.[hash].js) for this route
  19. // which is lazy-loaded when the route is visited.
  20. component: () => import(/* webpackChunkName: "about" */ '../views/Blog.vue')
  21. },
  22. {
  23. path: '/photo',
  24. name: 'Photo',
  25. // route level code-splitting
  26. // this generates a separate chunk (about.[hash].js) for this route
  27. // which is lazy-loaded when the route is visited.
  28. component: () => import(/* webpackChunkName: "photo" */ '../views/Photo.vue')
  29. }
  30. ]
  31. // 2.创建路由对象
  32. const router = new VueRouter({
  33. routes
  34. })
  35. export default router
  1. 注册 router 对象
    在 main.js 中创建 vue 实例并把 router对象传进去。
  1. import Vue from 'vue'
  2. import App from './App.vue'
  3. import router from './router'
  4. Vue.config.productionTip = false
  5. new Vue({
  6. router,
  7. render: h => h(App)
  8. }).$mount('#app')
  1. 创建路由组件的占位
    App.vue 中引入 <router-view/>标签。页面嵌套就由这个组件实现。
  2. 创建链接
    App.vue 中引入 <router-link>标签。这个并不是必要的,只是按需引入一些组件。
  1. <template>
  2. <div id="app">
  3. <div>
  4. <img src="@/assets/logo.png">
  5. </div>
  6. <div id="nav">
  7. <!-- 5. 创建链接 -->
  8. <router-link to="/">Index</router-link> |
  9. <router-link to="/blog">Blog</router-link> |
  10. <router-link to="/photo">Photo</router-link>|
  11. </div>
  12. <!-- 4. 创建路由组件的展占位 -->
  13. <router-view/>
  14. </div>
  15. </template>
  16. <style>
  17. #app {
  18. font-family: Avenir, Helvetica, Arial, sans-serif;
  19. -webkit-font-smoothing: antialiased;
  20. -moz-osx-font-smoothing: grayscale;
  21. text-align: center;
  22. color: #2c3e50;
  23. }
  24. #nav {
  25. padding: 30px;
  26. }
  27. #nav a {
  28. font-weight: bold;
  29. color: #2c3e50;
  30. }
  31. #nav a.router-link-exact-active {
  32. color: #42b983;
  33. }
  34. </style>

动态路由

例如 Detail 组件,对于不同 ID 的详情,都要使用这个组件来渲染。在路由路径中使用“动态路径参数”就能达到这种效果。

  1. const routes = [
  2. {
  3. path: '/',
  4. name: 'Index',
  5. component: Index
  6. },
  7. {
  8. // 动态路由
  9. path: '/detail/:id',
  10. name: 'Detail',
  11. // 开启 props,会把 URL 中的参数传递给组件
  12. // 在组件中通过 props 来接收 URL 参数
  13. props: true,
  14. // route level code-splitting
  15. // this generates a separate chunk (about.[hash].js) for this route
  16. // which is lazy-loaded when the route is visited.
  17. component: () => import(/* webpackChunkName: "detail" */ '../views/Detail.vue')
  18. }
  19. ]

组件接收参数时有两种方式:

  1. 通过当前路由规则获取,但是这种方式强依赖于路由。
  2. 通过在路由规则数组里开启 Detail 的 props 属性来获取。 ```vue

``` # 嵌套路由 当多个组件有共同的渲染部分,比如头部是导航,尾部是网站备案信息,可以把它们提取出来形成一个新的组件,然后组件中间留一个 `router-view`标签,用于组件的占位。这些有共同部分的组件作为新组件的子组件,以后加载在新组件的`router-view`标签的位置。子组件写路由规则时,可以是相对路径,也可以是绝对路径。 ```vue
  1. ```javascript
  2. const routes = [
  3. {
  4. name: 'login',
  5. path: '/login',
  6. component: Login
  7. },
  8. // 嵌套路由
  9. {
  10. path: '/',
  11. component: Layout,
  12. children: [
  13. {
  14. name: 'index',
  15. path: '',
  16. component: Index
  17. },
  18. {
  19. name: 'detail',
  20. path: 'detail/:id',
  21. props: true,
  22. component: () => import('@/views/Detail.vue')
  23. }
  24. ]
  25. }
  26. ]

编程式导航

除了使用 <router-link>创建 a 标签来定义导航链接以外,还可以借助 router 的实例方法来实现组件加载。
常用的方法有 $router.push()$router.replace()$router.go()等,事实上当点击<router-link>时,内部调用的就是 $router.push()方法。另外,<router-link to= "..." replace>相当于 $router.replace()

  1. <template>
  2. <div class="home">
  3. <div id="nav">
  4. <router-link to="/">Index</router-link>
  5. </div>
  6. <button @click="replace"> replace </button>
  7. <button @click="goDetail"> Detail </button>
  8. </div>
  9. </template>
  10. <script>
  11. export default {
  12. name: 'Index',
  13. methods: {
  14. replace () {
  15. this.$router.replace('/login')
  16. },
  17. goDetail () {
  18. this.$router.push({ name: 'Detail', params: { id: 1 } })
  19. }
  20. }
  21. }
  22. </script>

$router.push$router.replace都可以传入字符串或对象。如果提供了path,那么 params不会生效。namepath都能使用query传参,但是会变成 url 参数,使用动态路由的话,不能用query。所以动态路由可以使用name+params或者使用path+ 字符串拼接或者直接使用字符串拼接。

  1. const userId = '123'
  2. // 动态路由可用的模式
  3. router.push(`/user/${userId}`) // 直接传字符串 -> /user/123
  4. router.push({ name: 'user', params: { userId }}) // -> /user/123
  5. router.push({ path: `/user/${userId}` }) // -> /user/123
  6. // 这里的 params 不生效
  7. router.push({ path: '/user', params: { userId }}) // -> /user
  8. // 带查询参数,变成 /register?plan=private
  9. router.push({ path: 'register', query: { plan: 'private' }})

Hash 模式和 History 模式

  1. URL 的区别:Hash 模式的 URL 带了一个 # 号,可以携带问号和 url 参数,History 模式不带 # 号。
  1. const hashStyle = 'https://music.163.com/#/playlist?id=310321893'
  2. const historyStyle = 'https://music.163.com/playlist/310321893'
  1. Hash 模式是基于锚点以及 onhashchange 实现的,以锚点的值作为路由地址,当锚点变化,触发 onhashchage 事件,根据当前的路由地址找到对应组件重新渲染,如果改变 # 号后面的内容,浏览器不会向服务器发出请求,但是会把它加入访问历史;History 模式基于 Html5 的 API实现,history.pushState()history.replaceState()。调用history.pushState()时,浏览器不会向服务器发出请求,只会替换地址栏的 url,并且添加历史记录。通过监听 popstate 事件,可以获取到浏览器历史操作的变化,在 popstate 事件的处理函数中,可以获取改变后的地址,根据当前路由地址找到对应组件重新渲染。需要注意的是 popstate 只有在点击浏览器的前进和后退,以及调用 history.back()histoty.forward()时才会出发。

History 模式

History 模式需要服务器支持。因为 Vue 应用是单页应用,如果服务器没有配置,访问一个不存在的地址或点击浏览器的刷新按钮会返回 404 或“找不到该页面”,比如要访问 http://yoursite.com/user/id 输入错误变成 http://yoursite.com/userid,或者在http://yoursite.com/user/id刷新页面。因此,服务器端应该配置匹配不到任何静态资源就返回index.html页面。

Vue 项目默认开启 Hash 模式,在实例化 router 对象的时候,传入 mode 参数,可以控制要使用的模式。

  1. const router = new VueRouter({
  2. mode: 'history',
  3. routes: [...]
  4. })

启用了 History 模式后,服务器就不再返回 404 页面,不能匹配的请求都会返回 index.html。为了避免这种情况,应该在路由规则里添加一条覆盖所有路由情况的规则,返回自己实现的 404 页面。

  1. const routes = [
  2. {
  3. path: '*',
  4. name: '404',
  5. component: () => import(/* webpackChunkName: "404" */ '../views/404.vue')
  6. }
  7. ]
  8. const router = new VueRouter({
  9. mode: 'history',
  10. routes
  11. })

Node.JS 环境

模拟在 Node.JS 环境下,运行打包后生成的 web应用。connect-history-api-fallback就是用来处理 history 模式的模块。

  1. const path = require('path')
  2. // 导入处理 history 模式的模块
  3. const history = require('connect-history-api-fallback')
  4. // 导入 express
  5. const express = require('express')
  6. const app = express()
  7. // 注册处理 history 模式的中间件
  8. app.use(history())
  9. // 处理静态资源的中间件,网站根目录 ../web
  10. app.use(express.static(path.join(__dirname, '../web')))
  11. // 开启服务器,端口是 3000
  12. app.listen(3000, () => {
  13. console.log('服务器开启,端口:3000')
  14. })

Nginx 服务器

Nginx 默认没有支持 History 模式,所以刷新页面或者访问不存在的页面会返回 404,需要修改 nginx 配置。
需要修改的文件是/Nginx根目录/conf/nginx.conf,找到项目对应的 server,配置try_files查找文件的顺序。首先查找是否有这个文件,没有的话查找是否有这个文件夹,再没有直接返回 index,.html。

  1. server {
  2. listen 80;
  3. server_name localhost;
  4. #charset koi8-r;
  5. #access_log logs/host.access.log main;
  6. location / {
  7. root html;
  8. index index.html index.htm;
  9. try_files $uri $uri/ /index.html;
  10. }
  11. }