如何使用VueRouter在视图之间导航

来自菜鸟教程
跳转至:导航、​搜索

作者选择 Open Sourcing Mental Illness 作为 Write for DOnations 计划的一部分来接受捐赠。

介绍

大多数网站或应用程序都有多个静态或动态生成的 HTML 页面。 对于更传统的网站,每个 URL 路由有一个 文档对象模型 (DOM) 和一个页面。 然而,对于 单页应用程序 ,每个“页面”或视图都在一个 HTML 页面中呈现。 像 Vue.js 这样的用户界面 (UI) 框架在需要时通过使用虚拟 DOM 呈现这些页面和组件。 这个 Virtual DOM[X20X] 是原始 DOM 的 JavaScript 表示,客户端更容易更新。

当用户访问单页应用程序时,该应用程序会将自己与虚拟 DOM 进行比较,并仅重新渲染网页中更改的部分。 此技术可防止在单击链接时页面闪烁白色。 假设您在网页上有三个部分:页眉、内容和页脚。 当您导航到另一个 URL 时,Vue 将仅呈现应用程序在页面之间发生更改的内容区域。

在 Vue.js 中,您可以使用第一方库 Vue Router 创建多个视图。 该路由器与 URL 的视图建立关联。 在本教程中,您将学习如何添加 Vue Router 库,将其集成到您的项目中,并创建动态生成的路由。 您还将了解作为开发人员可用的不同类型的路线。 完成后,您将拥有一个可以使用多种方法导航的应用程序。

为了说明这些概念,您将创建一个显示机场信息的小型应用程序。 当用户点击机场卡时,应用程序将导航到机场详细信息的动态视图。 为此,程序将读取一个 URL 参数并根据该参数过滤掉数据。

先决条件

要完成本教程,您需要:

第 1 步 — 设置示例应用程序

您要构建的用于学习 Vue Router 的应用程序将需要一些初始数据。 在此步骤中,您将创建和构建此数据,以便在教程后面的 Vue 应用程序中访问。

要添加此数据集,您需要创建一个 data 目录并创建一个名为 airports.js 的 JavaScript 文件。 如果你不在src目录下,先进入cd

cd src

然后创建一个 data 目录:

mkdir data

现在创建一个 data/airports.js 文件并在文本编辑器中打开它。

添加以下内容为您的应用程序创建数据:

机场代码/src/data/airports.js

export default [
  {
    name: 'Cincinnati/Northern Kentucky International Airport',
    abbreviation: 'CVG',
    city: 'Hebron',
    state: 'KY',
      destinations: {
      passenger: [ 'Toronto', 'Seattle/Tacoma', 'Austin', 'Charleston', 'Denver', 'Fort Lauderdale', 'Jacksonville', 'Las Vegas', 'Los Angeles', 'Baltimore', 'Chicago', 'Detroit', 'Dallas', 'Tampa' ],
        cargo: [ 'Anchorage', 'Baltimore', ' Chicago' , 'Indianapolis', 'Phoenix', 'San Francisco', 'Seattle', 'Louisville', 'Memphis' ]
      }
  },
  {
    name: 'Seattle-Tacoma International Airport',
    abbreviation: 'SEA',
    city: 'Seattle',
    state: 'WA',
      destinations: {
      passenger: [ 'Dublin', 'Mexico City', 'Vancouver', 'Albuquerque', 'Atlanta', 'Frankfurt', 'Amsterdam', 'Salt Lake City', 'Tokyo', 'Honolulu' ],
        cargo: [ 'Spokane', 'Chicago', 'Dallas', ' Shanghai', 'Cincinnati', 'Luxenbourg', 'Anchorage', 'Juneau', 'Calgary', 'Ontario' ]
      }
  },
  {
    name: 'Minneapolis-Saint Paul International Airport',
    abbreviation: 'MSP',
    city: 'Bloomington',
    state: 'MN',
      destinations: {
      passenger: [ 'Dublin', 'Paris', 'Punta Cana', 'Winnipeg', 'Tokyo', 'Denver', 'Tulsa', 'Washington DC', 'Orlando', 'Mexico City' ],
        cargo: [ 'Cincinnati', 'Omaha', 'Winnipeg', 'Chicago', 'St. Louis', 'Portland', 'Philadelphia', 'Milwaukee', 'Ontario' ]
      }
  }
]

该数据是由美国的几个机场组成的 objectsarray。 在此应用程序中,您将遍历此数据以生成包含 name abbreviationcitystate 属性的卡片。 当用户单击卡片时,您将使用 Vue Router 将它们路由到动态视图并从其中一个属性中读取。 从那里,您将创建一个嵌套路由来显示存储在 destination 属性中的信息。

保存并退出文件。

接下来,在名为 views 的目录中创建一个 Home.vue 组件。 您可以通过打开终端并使用 mkdirtouch 命令来创建此目录和组件。

运行以下命令来创建目录:

mkdir views

然后创建 Home.vue 文件:

touch views/Home.vue

这个 Home.vue 组件将作为这个应用程序的主页。 在其中,您将利用 v-for 指令遍历 airports.js 数据集并在卡片中显示每个机场。

将以下代码添加到 Home.vue

机场代码/src/views/Home.vue

<template>
  <div class="wrapper">
    <div v-for="airport in airports" :key="airport.abbreviation" class="airport">
      <p>{{ airport.abbreviation }}</p>
      <p>{{ airport.name }}</p>
      <p>{{ airport.city }}, {{ airport.state }}</p>
    </div>
  </div>
</template>

<script>
import { ref } from 'vue'
import allAirports from '@/data/airports.js'

export default {
  setup() {
    const airports = ref(allAirports)
        return { airports }
    }
}
</script>

<style>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
.wrapper {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  grid-column-gap: 1rem;
  max-width: 960px;
  margin: 0 auto;
}
.airport {
  border: 3px solid;
  border-radius: .5rem;
  padding: 1rem;
}
.airport p:first-child {
  font-weight: bold;
  font-size: 2.5rem;
  margin: 1rem 0;
}
.airport p:last-child {
  font-style: italic;
  font-size: .8rem;
}
</style>

您可能会注意到此代码片段中包含一些 CSS。 在 Home.vue 组件中,您正在遍历机场集合,每个机场都分配有 airport 的 CSS 类。 这个 CSS 为生成的 HTML 添加了一些样式,通过制作边框为每个机场提供卡片的外观。 :first-child:last-child 选择器,它们对 div 内部 HTML 中的第一个和最后一个 p 标记应用不同的样式具有 airport 的类。

保存并关闭文件。

现在您已经创建了与本地数据集一起创建的初始视图,您将在下一步安装 Vue Router。

第 2 步 — 安装 Vue 路由器

有几种方法可以安装 Vue Router。 如果您使用 Vue CLI 从头开始创建新项目,可以在提示符中选择 Vue Router; 然后 Vue CLI 将为您安装和配置它。 但是,在本教程中,假设您没有在 CLI 设置中选择 Vue Router 选项。 您将改为通过 npm 安装 Vue 路由器。

要安装 Vue Router,首先从 src 目录移回项目目录的根目录:

cd ..

然后在项目根目录的终端窗口中运行以下命令:

npm i vue-router@next

您可能会注意到此命令中的 @next。 由于这个项目使用了 Vue 3 和 Composition API,你告诉 npm 下载这个库的最新实验版本。 如果您想了解有关当前版本的更多信息,请查看 GitHub 上的 Vue 路由器发布页面。

这将从 npm 下载 vue-router 库并将其添加到您的 package.json 文件中,以便在您下次运行 npm install 时自动下载。

下一步是创建您的路线文件。 该文件将包含用户可以导航到的所有可能路线。 当在 URL 栏中访问某个路由时,与该 URL 路由关联的组件将被挂载。

在您的终端中,在 src 目录中,移动到 src 目录并创建一个 router 目录:

cd src
mkdir router

接下来,在 router 目录下创建一个 index.js 文件:

touch router/index.js

在您选择的编辑器中打开您刚刚创建的文件。 首先要做的是 import Vue 路由器库。 实际上,您无需访问此库中的所有内容即可创建路由。 您可以选择 destructure 或仅导入所需的内容以最小化包大小。 在这种情况下,您需要 vue-router 中的两个函数:createWebHistorycreateRouter。 这些函数分别创建用户可以返回的历史记录并为 Vue 构造路由器对象。

将以下代码添加到 router/index.js

机场代码/src/router/index.js

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

接下来,添加以下突出显示的行以创建和导出您的路由器:

机场代码/src/router/index.js

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

const router = createRouter({
  history: createWebHistory(),
})

export default router

此文件将导出从 createRouter 函数返回的路由器对象。 您传入的对象有两个属性:historyrouteshistory 属性包含从 createWebHistory 生成的历史记录,而 routes 是一个对象数组。 您将在本教程后面添加 routes

接下来,导入 Home 视图并创建一个对象数组,将它们存储到名为 routesconst 中:

机场代码/src/router/index.js

import { createWebHistory, createRouter } from "vue-router"
import Home from "@/views/Home.vue"

const routes = [
  {
    path: "/",
    name: "Home",
    component: Home,
  },
]

const router = createRouter({ ... })

export default router

每条路由都是一个具有三个属性的对象:

  • path:URL地址
  • name:一个指定的名称来引用您项目中的路线
  • component:在浏览器的网址栏输入path时挂载的组件

现在您的 routes 数组已创建,您需要将其添加到导出的 router 对象中。

history 键/值对之后,添加 routes。 这是 JavaScript 中 routes: routes 的简写:

机场代码/src/router/index.js

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

const routes = [ ... ]

const router = createRouter({
  history: createWebHistory(),
  routes
})

export default router

至此,Vue Router 已经集成到你的项目中,并且你已经注册了一个路由。 保存并退出文件。

在另一个终端中,运行以下命令以在本地计算机上启动开发服务器:

npm run serve

如果您在浏览器窗口中访问 localhost:8080/,您还不会看到 Home.vue 组件。 这个集成过程的最后一步是告诉 Vue 监听这个 router/index.js 文件并在引用 <router-view /> 的地方注入已安装的组件。 为此,您需要在应用程序的 src/main.js 文件中引用它。

首先,打开src/main.js。 然后添加以下突出显示的行:

机场代码/src/main.js

import { createApp } from 'vue'
import App from './App.vue'
import router from './router'

createApp(App).use(router).mount('#app')

有了这个链接到 createApp.use() 函数,Vue.js 现在正在监听路由变化并利用你的 src/router/index.js 文件。 但是,Vue Router 无法显示挂载的 Home.vue 组件。 为此,您需要在 App.vue 文件中添加 router-view 组件。 该组件告诉 Vue Router 挂载与 <router-view /> 所在的路由关联的任何组件。

保存并退出 main.js 文件。

接下来,打开 App.vue 文件。 删除默认内容并将其替换为以下内容:

机场代码/src/App.vue

<template>
  <router-view />
</template>

保存并退出文件。

现在在浏览器中访问 localhost:8080/。 您会发现渲染的 Home.vue 组件,如下图所示:

Vue Router 现在已下载并与注册路由集成。 在下一节中,您将创建其他路由,包括两个内部页面和一个默认的 404 页面(如果未检测到路由)。

第 3 步 - 创建内部页面

此时,您的 App.vue 可以渲染在 src/router/index.js 文件中配置的任何组件。 使用 Vue CLI 生成的项目时,为您创建的目录之一是 views。 该目录包含任何直接映射到 router/index.js 文件中的路由的 .vue 组件。 重要的是要注意这不是自动完成的。 您需要在路由器文件中创建一个 .vueimport 以进行注册,如前所述。

在定义所有其他路由之前,您可以创建 default 路由。 在本教程中,此默认路由将充当 404 - Not Found 页面 - 在未找到路由的情况下的后备。

首先,创建将充当 404 页面的视图。 进入views目录:

cd views

然后创建一个名为 PageNotFound.vue 的文件:

touch PageNotFound.vue

在您的文本编辑器中,打开您刚刚创建的 PageNotFound.vue 文件。 添加以下 HTML 代码,为视图提供要呈现的内容:

机场代码/src/views/PageNotFound.vue

<template>
  <div>
    <h1>404 - Page Not Found</h1>
    <p>This page no longer exists or was moved to another location.</p>
  </div>
</template>

保存并关闭文件。

现在已经创建了 PageNotFound.vue 组件,是时候为您的应用程序创建一个包罗万象的路由了。 在文本编辑器中打开 src/router/index.js 文件并添加以下突出显示的代码:

机场代码/src/router/index.js

import { createWebHistory, createRouter } from "vue-router"
import Home from "@/views/Home.vue"
import PageNotFound from '@/views/PageNotFound.vue'

const routes = [
  {
    path: "/",
    name: "Home",
    component: Home,
  },
  {
    path: '/:catchAll(.*)*',
    name: "PageNotFound",
    component: PageNotFound,
  },
]
...

Vue 3 的 Vue 路由器使用自定义的 RegExpath 的值包含这个新的 RegEx,它告诉 Vue 为每个路由渲染 PageNotFound.vue,除非路由已经定义。 该路由中的 catchAll 指的是 Vue Router 内部的一个动态段,而 (.*) 是一个捕获任何字符串的正则表达式。

保存此文件并在浏览器窗口 localhost:8080/not-found 中访问您的应用程序。 您会在浏览器中找到 PageNotFound.vue 组件,如下图所示:

随意将此 URL 更改为其他任何内容; 你会得到同样的结果。

在继续之前,为您的应用程序创建另一个路由。 这条路线将是一个 about 页面。

打开您选择的终端并在 views 目录中创建文件:

touch About.vue

在您的文本编辑器中,打开您刚刚创建的 About.vue 文件。 添加以下 HTML 以创建有关您网站的更多信息:

机场代码/src/views/About.vue

<template>
  <div>
    <h1>About</h1>
    <p>This is an about page used to illustrate mapping a view to a router with Vue Router.</p>
  </div>
</template>

保存并关闭文件。

创建该视图后,在文本编辑器中打开 src/router/index.js 文件,导入 About.vue 组件,并使用 /about 的路径注册新路由:

机场代码/src/router/index.js

import { createWebHistory, createRouter } from "vue-router"
import Home from '@/views/Home.vue'
import About from '@/views/About.vue'
import PageNotFound from '@/views/PageNotFound.vue'

...
const routes = [
  {
    path: "/",
    name: "Home",
    component: Home,
  },
  {
    path: '/about',
    name: "About",
    component: About,
  },
  {
    path: '/:catchAll(.*)*',
    name: "PageNotFound",
    component: PageNotFound,
  },
]
...

保存并关闭文件。

此时,您有三种不同的路线:

  • localhost:8080/,路由到 Home.vue
  • localhost:8080/about,路由到 About.vue
  • 任何其他路由,默认情况下会转到 PageNotFound.vue

保存此文件后,打开浏览器并首先访问 localhost:8080/。 应用程序加载后,您将找到 Home.vue 的内容:机场卡集合。

通过访问 localhost:8080/about 继续测试这些路线。 这是一条静态路由,因此您会发现 About.vue 组件的内容,此时该组件包含一个标题和一个段落。

接下来,您可以通过访问浏览器中的其他任何内容来测试 PageNotFound.vue 组件。 例如,如果您访问 localhost:8080/some-other-route,Vue Router 将默认使用该 catchAll 路由,因为该路由未定义。

正如此步骤所示,Vue Router 是一个方便的第一方库,它呈现与特定路由关联的组件。 在这一步中,这个库是通过main.js文件全局下载和集成的,并在你的src/router/index.js文件中配置。

到目前为止,您的大部分路线都是 exact 路线。 这意味着只有当 URL 片段与路由器的 path 完全匹配时,组件才会挂载。 但是,还有其他类型的路由有自己的用途,可以动态生成内容。 在下一步中,您将实现不同类型的路由并了解何时使用其中一种。

第 4 步 — 使用参数创建路由

此时,您已经创建了两条精确路由和一条到 404 页面的动态路由。 但是 Vue Router 不仅仅拥有这些类型的路由。 您可以在 Vue Router 中使用以下路由:

  • 动态路由:具有动态参数的路由,您的应用程序可以引用这些参数来加载唯一数据。
  • 命名路由:可以使用 name 属性访问的路由。 此时创建的所有路由都具有 name 属性。
  • 嵌套路由:具有与其关联的子级的路由。
  • 静态或精确路由:具有静态 path 值的路由。

在本节中,您将创建一条显示各个机场信息的动态路线和一条用于机场目的地的嵌套路线。

动态路线

当您想要重用视图以根据路线显示不同的数据时,动态路线很有用。 例如,如果您想创建一个根据 URL 栏中的机场代码显示机场信息的视图,您可以使用动态路线。 在此示例中,如果您要访问 localhost:8080/airport/cvg 的路线,您的应用程序将显示来自机场的数据,代码为 cvg,即辛辛那提/北肯塔基国际机场。 接下来,您将按照说明创建此视图。

打开终端并使用 touch 命令创建一个新的 .vue 文件。 如果 src 是您当前的工作目录,则命令将如下所示:

touch views/AirportDetail.vue

创建之后,在您选择的文本编辑器中打开此文件。 继续创建你的 templatescript 标签来设置这个组件:

机场代码/src/views/AirportDetail.vue

<template>
  <div>
    
  </div>
</template>

<script>
export default {
  setup() { }
}
</script>

保存并关闭此文件。

接下来,您需要在 src/router/index.js 文件中注册此视图。 在文本编辑器中打开此文件,然后添加以下突出显示的行:

机场代码/src/router/index.js

import Home from '@/views/Home.vue'
import About from '@/views/About.vue'
import AirportDetail from '@/views/AirportDetail.vue'
import PageNotFound from '@/views/PageNotFound.vue'

...
const routes = [
  {
    path: "/",
    name: "Home",
    component: Home,
  },
  {
    path: '/about',
    name: "About",
    component: About,
  },
  {
    path: '/airport/:code',
    name: "AirportDetail",
    component: AirportDetail,
  },
  {
   path: '/:catchAll(.*)*',
   name: "PageNotFound",
   component: PageNotFound,
  },
]
...

这条新路由中的 :code 称为 参数。 参数是可以通过此名称在应用程序中访问的任何值。 在这种情况下,您有一个名为 code 的参数。 接下来,您将利用此参数显示与此缩写相关的信息。

保存并关闭此文件。

现在您有了一些数据,再次打开 AirportDetail.vue 组件。 在此组件中导入机场数据:

机场代码/src/views/AirportDetail.vue

...
<script>
import airports from '@/data/airports.js'

export default {
  setup() { }
}
</script>

接下来,创建一个计算属性,如果该对象的 abbreviation 属性与 URL 中的 :code 参数匹配,则从数组中返回一个对象。 在 Vue 3 中,您需要从 vue 库中解构 computed

机场代码/src/views/AirportDetail.vue

...
<script>
import { computed } from 'vue'
import { useRoute } from 'vue-router'
import airports from '@/data/airports.js'

export default {
  setup() {
  const route = useRoute()
    const airport = computed(() => {
        return airports.filter(a => a.abbreviation === route.params.code.toUpperCase())[0]
    })

    return { airport }
  }
}
</script>

如果满足条件,此计算属性使用 JavaScript 中的 filter 数组方法 返回一个对象数组。 由于您只需要一个对象,因此代码将始终返回第一个对象,它将使用 [0] 索引语法访问该对象。 route.params.code 是您访问路由器文件中定义的参数的方式。 为了访问路由的属性,您需要从 vue-router 导入一个名为 useRoute 的函数。 现在,当访问一条路线时,您可以立即访问该路线的所有属性。 您正在使用点符号来访问此 code 参数并检索其值。

此时,如果 URL 中的代码与 abbreviation 属性匹配,则此计算属性将返回单个机场对象。 这意味着您可以访问机场的所有对象属性,并且可以构造该组件的 template

继续在文本编辑器中编辑 AirportDetail.vue 文件并构建模板以显示机场信息:

机场代码/src/views/AirportDetail.vue

<template>
 <div>
   <p>{{ airport.name }} ({{ airport.abbreviation }})</p>
   <p>Located in {{ airport.city }}, {{ airport.state }}</p>
 </div>
</template>
...

打开浏览器并访问 localhost:8080/airport/sea。 与西雅图-塔科马国际机场相关的信息将在您的浏览器中呈现,如下图所示:

嵌套路由

随着应用程序的增长,您可能会发现您有许多与父级相关的路由。 与用户相关的一系列路线就是一个很好的例子。 如果有一个名为 foo 的用户,您可以为同一个用户有多个嵌套路由,每个路由都以 /user/foo/ 开头。 当用户在 /user/foo/profile 路线上时,用户将查看与他们关联的个人资料页面。 用户的 posts 页面可能具有 /user/foo/posts 的路由。 这种嵌套可以使您能够将您的路线与您的组件一起组织。 有关这方面的更多信息,请查看 Vue 路由器文档

您可以将相同的模式应用于您在本教程中构建的应用程序。 在本节中,您将添加一个视图以显示每个机场支持的目的地。

打开终端,在 src 目录中,创建一个名为 AirportDestinations.vue 的新文件:

touch views/AirportDestinations.vue

接下来,打开您的文本编辑器并添加以下内容:

机场代码/src/views/AirportDestinations.vue

<template>
  <h1>Destinations for {{ airport.name }} ({{ airport.abbreviation }}</h1>
  <h2>Passenger</h2>
  <ul>
    <li v-for="(destination, i) in airport.destinations.passenger" :key="i">
      {{ destination }}
    </li>
  </ul>
  <h2>Cargo</h2>
  <ul>
    <li v-for="(destination, i) in airport.destinations.cargo" :key="i">
      {{ destination }}
    </li>
  </ul>
</template>

<script>
  import { computed } from 'vue'
  import { useRoute } from 'vue-router'
  import airports from '@/data/airports.js'

  export default {
    setup() {
      const route = useRoute()
      const airport = computed(() => {
        return airports.filter(a => a.abbreviation === route.params.code.toUpperCase())[0]
      })
    return { airport }
  }
}
</script>

此视图将呈现 airports.js 文件中每个机场的所有目的地。 在此视图中,您正在使用 v-for 指令来遍历目标。 与 AirportDetail.vue 视图非常相似,您正在创建一个名为 airport 的计算属性,以获取与 URL 栏中的 :code 参数匹配的机场。

保存并关闭文件。

要创建嵌套路由,您需要将 children 属性添加到 src/router/index.js 文件中的路由对象。 子(嵌套)路由对象包含与其父对象相同的属性。

打开 router/index.js 并添加以下突出显示的行:

机场代码/src/router/index.js

import Home from '@/views/Home.vue'
import About from '@/views/About.vue'
import AirportDetail from '@/views/AirportDetail.vue'
import AirportDestinations from '@/views/AirportDestinations.vue'
import PageNotFound from '@/views/PageNotFound.vue'

...
const routes = [
    ...
  {
    path: '/airport/:code',
    name: "AirportDetail",
    component: AirportDetail,
        children: [
            {
              path: 'destinations',
                name: 'AirportDestinations',
                component: AirportDestinations
            }
        ]
  },
    ...
]
...

此子路由的 path 与其父路由相比较短。 这是因为,使用嵌套路由,您不需要添加整个路由。 子代继承其父代的 path 并将其添加到子代 [X75X] 之前。

打开浏览器窗口,然后访问 localhost:8080/airport/msp/destinations。 与父级 AirportDetails.vue 似乎没有什么不同。 那是因为在使用嵌套路由时,需要在父级中包含 <router-view /> 组件。 当访问子路由时,Vue 会将子视图中的内容注入到父视图中:

机场代码/src/views/AirportDetail.vue

<template>
 <div>
   <p>{{ airport.name }} ({{ airport.abbreviation }})</p>
   <p>Located in {{ airport.city }}, {{ airport.state }}</p>
     <router-view />
 </div>
</template>

在这种情况下,当在浏览器中访问目的地路线时,AirportDestinations.vue 将显示明尼阿波利斯-圣保罗国际机场支持的客运和货运航班目的地的无序列表。

在此步骤中,您创建了动态和嵌套路由,并学习了如何使用计算属性来检查 URL 栏中的 :code 参数。 现在所有路线都已创建,在最后一步中,您将通过使用 <router-link /> 组件创建链接来在不同类型的路线之间导航。

第 5 步 — 在路线之间导航

在使用单页应用程序时,您需要注意一些注意事项。 由于每个页面都被引导到单个 HTML 页面中,因此使用标准锚 (<a />) 在内部路由之间导航将不起作用。 相反,您需要使用 Vue Router 提供的 <router-link /> 组件。

与标准锚标记不同,router-link 提供了许多不同的方法来链接到应用程序中的其他路由,包括使用命名路由。 命名路由是具有关联的 name 属性的路由。 到目前为止,您创建的每个链接都有一个已关联的 name。 在此步骤的后面,您将学习如何使用 name 而不是 path 进行导航。

使用 <router-link /> 组件

当您最初将 Vue Router 集成到您的应用程序中时,<router-link /> 组件是全局导入的。 要使用这个组件,您需要将它添加到您的模板中并为其提供一个 prop 值。

在编辑器的 views 目录中打开 Home.vue 组件。 此视图显示您在 airports.js 文件中拥有的每个机场。 您可以使用 router-link 替换包含的 div 标记,以使每张卡片可点击到各自的详细视图。

将以下突出显示的行添加到 Home.vue

机场代码/src/views/Home.vue

<template>
    <div class="wrapper">
        <router-link v-for="airport in airports" :key="airport.abbreviation" class="airport">
            <p>{{ airport.abbreviation }}</p>
            <p>{{ airport.name }}</p>
            <p>{{ airport.city }}, {{ airport.state }}</p>
        </router-link>
    </div>
</template>
...

router-link 至少需要一个名为 to 的道具。 这个 to 属性接受具有多个键/值对的对象。 由于此卡使用 v-for 指令,因此这些卡是数据驱动的。 您需要能够导航到 AirportDetail.vue 组件。 如果您查看该组件的路径,则可以通过 /airports/:code 访问它。

通过 path 属性导航时,它是一对一的匹配。 添加以下突出显示的段:

机场代码/src/views/Home.vue

<template>
    <div class="wrapper">
        <router-link :to="{ path: `/airports/${airport.abbreviation}` }" v-for="airport in airports" :key="airport.abbreviation" class="airport">
            ...
        </router-link>
    </div>
</template>
...

在此代码中,您使用 JavaScript 字符串插值 动态插入机场代码作为 path 属性的值。 但是,随着应用程序规模的扩大,您可能会发现通过 path 导航到不同的路线并不是最好的方法。 事实上,使用命名路线进行导航通常被认为是最佳实践。

要实现命名路由,请在 path 上使用路由的 name。 如果你引用 src/router/index.js 你会发现 AirportDetail.vue 的名字是 AirportDetail

机场代码/src/views/Home.vue

<template>
    <div class="wrapper">
        <router-link :to="{ name: 'AirportDetail' }" v-for="airport in airports" :key="airport.abbreviation" class="airport">
            ...
        </router-link>
    </div>
</template>
...

使用命名路由而不是精确路由的好处是命名路由不依赖于路由的 path。 URL 结构在开发过程中总是会发生变化,但路由的名称很少会改变。

您可能会注意到,您无法像之前对确切路线所做的那样传递机场代码。 如果您需要将参数传递给命名路由,则需要添加 params 属性,该属性包含一个表示您的参数的对象:

机场代码/src/views/Home.vue

<template>
    <div class="wrapper">
        <router-link :to="{ name: 'AirportDetail', params: { code: airport.abbreviation } }" v-for="airport in airports" :key="airport.abbreviation" class="airport">
            ...
        </router-link>
    </div>
</template>
...

保存此文件并在浏览器中的 localhost:8080 中查看。 单击西雅图-塔科马机场卡现在将导航到 localhost:8080/airport/sea

程序化导航

当您需要导航到 HTML 模板中的另一个视图时,<router-link /> 组件非常有用。 但是,当您需要在 JavaScript 函数中的路由之间导航时,这些情况会怎样呢? Vue Router 为这个问题提供了一个解决方案,称为 programmatic navigation

在本教程的前面部分,您创建了一个名为 PageNotFound 的包罗万象的路由。 如果 airport 计算属性在 AirportDetail.vueAirportDestinations.vue 组件中返回 undefined,那么始终导航到该页面将是一种很好的用户体验。 在本节中,您将实现此功能。

在您的文本编辑器中,打开 AirportDetail.vue 组件。 为此,请检测 airport.value 是否未定义。 该函数将在组件首次挂载时调用,这意味着您将需要使用 Vue 的生命周期方法。

添加以下突出显示的行:

机场代码/src/views/AirportDetail.vue

<template>
  <div v-if="airport">
   <p>{{ airport.name }} ({{ airport.abbreviation }})</p>
   <p>Located in {{ airport.city }}, {{ airport.state }}</p>
   <router-view />
  </div>
</template>

<script>
    import { computed, onMounted } from 'vue'
    import { useRoute } from 'vue-router'
    import airports from '@/data/airports.js'
    import router from '@/router'

    export default {
            setup() {
        const route = useRoute()
                const airport = computed(() => {
                    return airports.filter(a => a.abbreviation === route.params.code.toUpperCase())[0]
                })
                    
                onMounted(() => {
                    if (!airport.value) {
                        // Navigate to 404 page here
                    }
                })
                    
                return { airport }
            }
    }
</script>

在这个 onMounted 函数中,您正在检查 airport.value 是否为假值。 如果是,则路由到 PageNotFound。 您可以像处理 router-link 组件一样处理编程路由。 由于不能在 JavaScript 函数中使用组件,因此需要使用 router.push({ ... })router 对象的 push 方法在使用链接组件时接受 to 属性的值:

/src/views/AirportDetail.vue

<script>
    ...
  onMounted(() => {
        if (!airport.value) {
            router.push({ name: 'PageNotFound' })
        }
  })
    ...
</script>

如果路由不存在,或者数据没有正确返回,这将保护用户免受损坏的网页的影响。

保存文件并导航到 localhost:8080/airport/ms。 由于 ms 不是数据中的机场代码,因此 airport 对象将未定义,路由器会将您重定向到 404 页面。

结论

在本教程中,您使用 Vue Router 创建了一个在不同视图之间路由的 Web 应用程序。 您学习了不同类型的路由,包括精确路由、命名路由和嵌套路由,以及使用 router-link 组件创建的带有参数的链接。 在最后一步中,您通过利用路由器的 push() 函数使用 JavaScript 提供了编程导航。

有关 Vue Router 的更多信息,建议阅读他们的文档。 CLI 工具特别具有本教程未涵盖的许多附加功能。 有关 Vue 的更多教程,请查看 Vue 主题页面