一、简单路由(不引入一整个路由库)

1、示例(动态组件切换的方式)

<script>
import Home from './Home.vue'
import About from './About.vue'
import NotFound from './NotFound.vue'
const routes = {
  '/': Home,
  '/about': About
}
export default {
  data() {
    return {
      currentPath: window.location.hash
    }
  },
  computed: {
    currentView() {
      return routes[this.currentPath.slice(1) || '/'] || NotFound
    }
  },
  mounted() {
    window.addEventListener('hashchange', () => {
		  this.currentPath = window.location.hash
		})
  }
}
</script>
<template>
  <a href="#/">Home</a> |
  <a href="#/about">About</a> |
  <a href="#/non-existent-path">Broken Link</a>
  <component :is="currentView" />
</template>

  子组件

<!-- Home.vue -->
<template>
  <h1>Home</h1>
</template>

<!-- About.vue -->
<template>
  <h1>About</h1>
</template>

<!-- NotFound.vue -->
<template>
  <h1>404</h1>
</template>

二、Vue Router基础知识(4.x)

1、概念

  Vue Router 是 Vue.js 的官方路由。它与 Vue.js 核心深度集成,让用 Vue.js 构建单页应用变得轻而易举。功能包括:

  • 嵌套路由映射
  • 动态路由选择
  • 模块化、基于组件的路由配置
  • 路由参数、查询、通配符
  • 展示由 Vue.js 的过渡系统提供的过渡效果
  • 细致的导航控制
  • 自动激活 CSS 类的链接
  • HTML5 history 模式或 hash 模式
  • 可定制的滚动行为
  • URL 的正确编码
1)Hash 模式(只看,不用运行示例)

  hash 模式是用 createWebHashHistory() 创建的。它在内部传递的实际 URL 之前使用了一个哈希字符(#)。由于这部分 URL 从未被发送到服务器,所以它不需要在服务器层面上进行任何特殊处理。不过,它在 SEO 中确实有不好的影响。如果你担心这个问题,可以使用 HTML5 模式。

import { createRouter, createWebHashHistory } from 'vue-router'

const router = createRouter({
  history: createWebHashHistory(),
  routes: [
    //...
  ],
})
2)HTML5 模式(只看,不用运行示例)

  用 createWebHistory() 创建 HTML5 模式,推荐使用这个模式。当使用这种历史模式时,URL 会看起来很 "正常",例如 https://example.com/user/id。漂亮!

  不过,问题来了。由于我们的应用是一个单页的客户端应用,如果没有适当的服务器配置,用户在浏览器中直接访问 https://example.com/user/id,就会得到一个 404 错误。这就尴尬了。不用担心:要解决这个问题,你需要做的就是在你的服务器上添加一个简单的回退路由。如果 URL 不匹配任何静态资源,它应提供与你的应用程序中的 index.html 相同的页面。漂亮依旧!

import { createRouter, createWebHistory } from 'vue-router'

const router = createRouter({
  history: createWebHistory(),
  routes: [
    //...
  ],
})

  nginx配置:

location / {
  try_files $uri $uri/ /index.html;
}

  其他配置见:服务器配置示例(可以学完这章后再进行研究)

2、安装

  npm install vue-router@4

3、简单使用(html;对标上面的简单路由)

  1)通过router-link指定 url 链接;

  2)通过router-view显示与 url 对应的组件;

<script src="https://unpkg.com/vue@3"></script>
<script src="https://unpkg.com/vue-router@4"></script>

<div id="app">
  <h1>Hello App!</h1>
  <p>
    <!--使用 router-link 组件进行导航 -->
    <!--通过传递 `to` 来指定链接 -->
    <!--`<router-link>` 将呈现一个带有正确 `href` 属性的 `<a>` 标签-->
    <router-link to="/">Go to Home</router-link>
    <router-link to="/about">Go to About</router-link>
  </p>
  <!-- 路由出口 -->
  <!-- 路由匹配到的组件将渲染在这里 -->
  <router-view></router-view>
</div>

4、Vue应用中使用路由(必须掌握的知识)

1)示例1:
// 1、定义路由组件;也可以从其他文件导入
const Home = { template: '<div>Home</div>' }
const About = { template: '<div>About</div>' }

// 2、定义一些路由
// 每个路由都需要映射到一个组件;我们后面再讨论嵌套路由。
const routes = [
  { path: '/', component: Home },
  { path: '/about', component: About },
]

// 3、创建路由实例并传递 `routes` 配置
const router = VueRouter.createRouter({
  history: VueRouter.createWebHashHistory(),  // 内部提供了 history 模式的实现。为了简单起见,我们在这里使用 hash 模式(推荐HTML5模式)。
  routes, // `routes: routes` 的缩写
})

// 4、创建Vue应用并挂载根实例
const app = Vue.createApp({})
app.use(router)    // 整个应用支持的路由;以this.$router 的形式访问。
app.mount('#app')  // 挂载

// 5、现在,应用已经启动了!
2)示例2(npm init vue@latest引导式创建的项目中的代码)
import { createRouter, createWebHistory } from 'vue-router'
import HomeView from '../views/HomeView.vue'

const router = createRouter({
  history: createWebHistory(import.meta.env.BASE_URL),
  routes: [
    {
      path: '/',
      name: 'home',
      component: HomeView
    },
    {
      path: '/about',
      name: 'about',
      // route level code-splitting
      // this generates a separate chunk (About.[hash].js) for this route
      // which is lazy-loaded when the route is visited.
      component: () => import('../views/AboutView.vue')
    }
  ]
})

export default router
3)Vue应用中访问路由组件

  在上面的Vue应用的任何地方都可以通过this.$route来访问路由组件,如: this.$router.push('/login')  // 跳转到login页

5、动态路由

路径参数用冒号 : 表示;下面为“现在像 /users/johnny 和 /users/jolyne 这样的 URL 都会映射到同一个路由。”的案例:

const User = {
  // 通过更新 User 的模板来呈现当前的用户 ID
  template: '<div>User {{ $route.params.id }}</div>',
}

// 这些都会传递给 `createRouter`
const routes = [
  // 动态字段以冒号开始
  { path: '/users/:id', component: User },
]

  1)多参数使用 路径拼接 的形式标识:/users/:username/posts/:postId(效果举例:/users/eduardo/posts/123)

  2)路由的匹配语法(介绍路由联合正则表达式、通配符*使用啥的;还有匹配区分大小写sensitive、匹配带有尾部斜线的路由路径strict

6、嵌套路由

1)嵌套前的根路由
<div id="app">
  <router-view></router-view>
</div>
js
const User = {
  template: '<div>User {{ $route.params.id }}</div>',
}

// 这些都会传递给 `createRouter`
const routes = [{ path: '/user/:id', component: User }]
2)嵌套后的路由

  ① 一个被渲染的组件也可以包含自己嵌套的 <router-view>。例如,我们可以在 User 组件的模板内添加一个 <router-view>

  ② 在路由中配置 children路由;

<div id="app">
  <router-view></router-view>
</div>

...
const User = {
  template: `
    <div class="user">
      <h2>User {{ $route.params.id }}</h2>
      <router-view></router-view>
    </div>
  `,
}
const routes = [
  {
    path: '/user/:id',
    component: User,
    children: [
      {
        // 当 /user/:id/profile 匹配成功
        // UserProfile 将被渲染到 User 的 <router-view> 内部
        path: 'profile',
        component: UserProfile,
      },
      {
        // 当 /user/:id/posts 匹配成功
        // UserPosts 将被渲染到 User 的 <router-view> 内部
        path: 'posts',
        component: UserPosts,
      },
    ],
  },
]

  ③ 更多见:嵌套的命名路由

7、页面导航

1)页面加载this.$router.push()
// 字符串路径
router.push('/users/eduardo')
router.push(`/user/${username}`) // -> /user/eduardo
    
// 带有路径的对象
router.push({ path: '/users/eduardo' })
router.push({ path: `/user/${username}` }) // -> /user/eduardo
    
// 命名的路由,并加上参数,让路由建立 url
router.push({ name: 'user', params: { username } }) // -> /user/eduardo
router.push({ name: 'user', params: { username: 'eduardo' } })
// `params` 不能与 `path` 一起使用
router.push({ path: '/user', params: { username } }) // -> /user  // 注:如果如果提供了 path,params 会被忽略
    
// 带查询参数,结果是 /register?plan=private
router.push({ path: '/register', query: { plan: 'private' } })

// 带 hash,结果是 /about#team
router.push({ path: '/about', hash: '#team' })

// 替换路由Url;相当于 router.replace({ path: '/home' })
router.push({ path: '/home', replace: true })
2)前进router.forward()
router.forward()  // 前进一步
3)后退router.back()
router.back()  // 后退一步
4)历史跳转router.go(n)
// 向前移动一条记录,与 router.forward() 相同
router.go(1)

// 返回一条记录,与 router.back() 相同
router.go(-1)

// 前进 3 条记录
router.go(3)

// 如果没有那么多记录,静默失败
router.go(-100)
router.go(100)

8、路由传参props

  通过props将值传递给路由组件

const User = {
  template: '<div>User {{ $route.params.id }}</div>'
}
const routes = [{ path: '/user/:id', component: User }]

  替换成

const User = {
  // 请确保添加一个与路由参数完全相同的 prop 名
  props: ['id'],
  template: '<div>User {{ id }}</div>'
}
const routes = [{ path: '/user/:id', component: User, props: true }]
1)传参模式 - 布尔模式

  当 props 设置为 true 时,route.params 将被设置为组件的 props。

// 对于有命名视图的路由,你必须为每个命名视图定义 props 配置
const routes = [
  {
    path: '/user/:id',  // :id是参数
    components: { default: User, sidebar: Sidebar },
    props: { default: true, sidebar: false }  // 这里是布尔模式的写法
  }
]
2)传参模式 - 对象模式
// 当 props 是一个对象时,它将原样设置为组件 props。当 props 是静态的时候很有用。
const routes = [
  {
    path: '/promotion/from-newsletter',
    component: Promotion,
    props: { newsletterPopup: false }  // 这里是对象模式的写法;newsletterPopup: false是参数
  }
]
3)传参模式 - 函数模式

   你可以创建一个返回 props 的函数。这允许你将参数转换为其他类型,将静态值与基于路由的值相结合等等。

const routes = [
  {
    path: '/search',
    component: SearchUser,
    props: route => ({ query: route.query.q })  // URL /search?q=vue 将传递 {query: 'vue'} 作为 props 传给 SearchUser 组件。
  }
]

9、路由重定向redirect

1)基础使用
// 1、从 /home 重定向到 /
const routes = [{ path: '/home', redirect: '/' }]

// 2、重定向的目标也可以是一个命名的路由
const routes = [{ path: '/home', redirect: { name: 'homepage' } }]

// 3、甚至是一个方法,动态返回重定向目标
const routes = [
  {
    // /search/screens -> /search?q=screens
    path: '/search/:searchText',
    redirect: to => {
      // 方法接收目标路由作为参数
      // return 重定向的字符串路径/路径对象
      return { path: '/search', query: { q: to.params.searchText } }
    },
  },
  {
    path: '/search',
    // ...
  },
]

// 4、
2)重定向到相对路径

  相对位置Url不以`/`开头

const routes = [
  {
    // 将总是把/users/123/posts重定向到/users/123/profile。
    path: '/users/:id/posts',
    redirect: to => {
      // 该函数接收目标路由作为参数
      // 相对位置不以`/`开头
      // 或 { path: 'profile'}
      return 'profile'
    },
  },
]
3)路径使用别名

  将 / 起一个别名 /home,意味着当用户访问 /home 时,URL 仍然是 /home,但是用户访问的为 /。示例如下:

const routes = [{ path: '/', component: Homepage, alias: '/home' }]

  通过别名,你可以自由地将 UI 结构映射到一个任意的 URL,而不受配置的嵌套结构的限制。数组示例如下:

const routes = [
  {
    path: '/users',
    component: UsersLayout,
    children: [
      // 为这 3 个 URL 呈现 UserList
      // - /users
      // - /users/list
      // - /people
      { path: '', component: UserList, alias: ['/people', 'list'] },
    ],
  },
]

  动态使用别名示例,如下:

const routes = [
  {
    path: '/users/:id',
    component: UsersByIdLayout,
    children: [
      // 为这 3 个 URL 呈现 UserDetails
      // - /users/24
      // - /users/24/profile
      // - /24
      { path: 'profile', component: UserDetails, alias: ['/:id', ''] },
    ],
  },
]

二、VueRouter进阶

  见:VueRouter进阶


作者:꧁执笔小白꧂