学不会Vue Router?那千万别错过这篇文章!

Mr侯_爱前端 -
学不会Vue Router?那千万别错过这篇文章!
入门

用 Vue + Vue Router 创建单页应用非常简单:通过 Vue.js,已经用组件组成了应用。当加入 Vue Router 时,将组件映射到路由上,让 Vue Router 知道在哪里渲染它们。

HTML
<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="/">Go to Home</router-link>
     <router-link to="/about">Go to About</router-link>
  </p>
  <router-view></router-view>
</div>
router-link

在这里没有使用常规的 a 标签,而是使用一个自定义组件 router-link 来创建链接。这使得 Vue Router 可以在不重新加载页面的情况下更改 URL,处理 URL 的生成以及编码。

router-view

router-view 显示与 url 对应的组件。可以把它放在任何地方,以适应你的布局。

JavaScript
const Home = { template: '<div>Home</div>' }
const About = { template: '<div>About</div>' }

const routes = [
  { path: '/', component: Home },
  { path: '/about', component: About },
]

const router = VueRouter.createRouter({
  history: VueRouter.createWebHashHistory(),
  routes, // `routes: routes` 的缩写
})

const app = Vue.createApp({})
app.use(router)
app.mount('#app')

通过调用 app.use(router),可以在任意组件中以 this.$router 的形式访问它,并且以 this.$route 的形式访问当前路由:

带参数的动态路由匹配

很多时候,需要将给定匹配模式的路由映射到同一个组件。在 Vue Router 中,可以在路径中使用一个动态字段来实现,称之为 路径参数 :

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

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

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

响应路由参数的变化

使用带有参数的路由时需要注意,当你从 /users/johnny 导航到/users/jolyne 时,相同的组件实例将被重复使用。因为两个路由都渲染同个组件,比起销毁再建,复用则显得更加高效。不过,这也意味着组件的生命周期钩子不会被调用。

要对同一个组件中参数的变化做出响应的话,可以简单地 watch $route 对象上的任意属性,在这个场景中,就是 $route.params :

const User = {
  template: '...',
  created() {
    this.$watch(
      () => this.$route.params,
      (toParams, previousParams) => {
        // 对路由变化做出响应...
      }
    )
  },
}
路由的匹配语法

大多数应用都会使用 /about 这样的静态路由和 /users/:userId 这样的动态路由,就像刚才在动态路由匹配中看到的那样,但是 Vue Router 可以提供更多的方式!

在参数中自定义正则

当定义像 :userId 这样的参数时,内部使用以下的正则 (如[ ^ / ]+) (至少有一个字符不是 / )来从 URL 中提取参数。当你需要根据参数的内容来区分两个路由,最简单的方法就是在路径中添加一个静态部分来区分它们:

const routes = [
  // 匹配 /o/3549
  { path: '/o/:orderId' },
  // 匹配 /p/books
  { path: '/p/:productName' },
]

但在某些情况下,不想添加静态的 /o /p 部分。由于,orderId 总是一个数字,而 productName 可以是任何东西,所以可以在括号中为参数指定一个自定义的正则:

const routes = [
  // /:orderId -> 仅匹配数字
  { path: '/:orderId(\\d+)' },
  // /:productName -> 匹配其他任何内容
  { path: '/:productName' },
]

现在,转到 /25 将匹配 /:orderId,其他情况将会匹配 /:productName。routes 数组的顺序并不重要!

可重复的参数

如果需要匹配具有多个部分的路由,如 /first/second/third,应该用 *(0 个或多个)和 +(1 个或多个)将参数标记为可重复:

const routes = [
  // /:chapters ->  匹配 /one, /one/two, /one/two/three, 等
  { path: '/:chapters+' },
  // /:chapters -> 匹配 /, /one, /one/two, /one/two/three, 等
  { path: '/:chapters*' },
]

这将会提供一个参数数组,而不是一个字符串,并且在使用命名路由时也需要传递一个数组:

可选参数

可以通过使用 ? 修饰符(0 个或 1 个)将一个参数标记为可选

const routes = [
  // 匹配 /users 和 /users/posva
  { path: '/users/:userId?' },
  // 匹配 /users 和 /users/42
  { path: '/users/:userId(\\d+)?' },
]

这里需要注意,* 在技术上也标志着一个参数是可选的,但 ? 参数不能重复。

调试

如果要探究路由是如何转化为正则的,以了解为什么一个路由没有被匹配,或者,报告一个 bug,可以使用路径排名工具。它支持通过 URL 分享路由。

嵌套路由

一些应用程序的 UI 由多层嵌套的组件组成。在这种情况下,URL 的片段通常对应于特定的嵌套组件结构,例如:

/user/johnny/profile                     /user/johnny/posts
+------------------+                  +-----------------+
| User             |                  | User            |
| +--------------+ |                  | +-------------+ |
| | Profile      | |  +------------>  | | Posts       | |
| |              | |                  | |             | |
| +--------------+ |                  | +-------------+ |
+------------------+                  +-----------------+

通过 Vue Router,可以使用嵌套路由配置来表达这种关系。

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

const User = {
  template: '<div>User {{ $route.params.id }}</div>',
}
// 这些都会传递给 `createRouter`
const routes = [{ path: '/user/:id', component: User }]

这里的 <router-view> 是一个顶层的 router-view。它渲染顶层路由匹配的组件。同样地,一个被渲染的组件也可以包含自己嵌套的 <router-view>。如果在 User 组件的模板内添加一个 <router-view>:

const User = {
  template: `
    <div >
      <h2>User {{ $route.params.id }}</h2>
      <router-view></router-view>
    </div>
  `,
}

要将组件渲染到这个嵌套的 router-view 中,需要在路由中配置 children:

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,
      },
    ],
  },
]

需要注意,以 / 开头的嵌套路径将被视为根路径。这允许利用组件嵌套,而不必使用嵌套的 URL。

如你所见,children 配置只是另一个路由数组,就像 routes 本身一样。因此,你可以根据自己的需要,不断地嵌套视图。

编程式导航

除了使用 <router-link> 创建 a 标签来定义导航链接,还可以借助 router 的实例方法,通过编写代码来实现。

导航到不同的位置

想要导航到不同的 URL,可以使用 router.push 方法。这个方法会向 history 栈添加一个新的记录,所以,当用户点击浏览器后退按钮时,会回到之前的 URL。

当点击 <router-link> 时,内部会调用这个方法,所以点击 <router-link :to="..."> 相当于调用 router.push(...) :

该方法的参数可以是一个字符串路径,或者一个描述地址的对象。

// 字符串路径
router.push('/users/eduardo')

// 带有路径的对象
router.push({ path: '/users/eduardo' })

// 命名的路由,并加上参数,让路由建立 url
router.push({ name: 'user', params: { username: 'eduardo' } })

// 带查询参数,结果是 /register?plan=private
router.push({ path: '/register', query: { plan: 'private' } })

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

如果提供了 path,params 会被忽略,上述的 query 并不属于这种情况。取而代之的是下面的做法,需要提供路由的 name 或手写完整的带有参数的 path :

const username = 'eduardo'
// 可以手动建立 url,但必须自己处理编码
router.push(`/user/${username}`) // -> /user/eduardo
// 同样
router.push({ path: `/user/${username}` }) // -> /user/eduardo
// 如果可能的话,使用 `name` 和 `params` 从自动 URL 编码中获益
router.push({ name: 'user', params: { username } }) // -> /user/eduardo
// `params` 不能与 `path` 一起使用
router.push({ path: '/user', params: { username } }) // -> /user

由于属性 to 与 router.push 接受的对象种类相同,所以两者的规则完全相同。

router.push 和所有其他导航方法都会返回一个 Promise,让我们可以等到导航完成后才知道是成功还是失败。

替换当前位置

它的作用类似于 router.push,唯一不同的是,它在导航时不会向 history 添加新记录,正如它的名字所暗示的那样——它取代了当前的条目。

也可以直接在传递给 router.push 的 routeLocation 中增加一个属性 replace: true :

router.push({ path: '/home', replace: true })
// 相当于
router.replace({ path: '/home' })
特别申明:本文内容来源网络,版权归原作者所有,如有侵权请立即与我们联系(cy198701067573@163.com),我们将及时处理。

Tags 标签

前端vue.jsvue3html5router

扩展阅读

加个好友,技术交流

1628738909466805.jpg