乐趣区

关于前端:学不会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 class="user">
      <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'})
退出移动版