简介
大多数网站或应用程序有多个静态或动态生成的HTML页面。对于更传统的网站,有一个文档对象模型(DOM),每个URL路由有一个页面。然而,对于_单页应用程序_,每个 “页面 “或视图都在一个HTML页面中呈现。像Vue.js这样的用户界面(UI)框架在需要时通过使用虚拟DOM渲染这些页面和组件。这个_虚拟DOM_是原始DOM的JavaScript表示,对客户端来说更容易更新。
当用户访问一个单页的应用程序时,该应用程序会将自己与虚拟DOM进行比较,并只重新渲染网页中被改变的部分。这种技术可以防止在点击链接时页面闪现白色。假设你在一个网页上有三个部分:页眉、内容和页脚。当你导航到另一个URL时,Vue将只渲染页面之间变化的应用程序的内容区。
在Vue.js中,你可以使用第一方库Vue Router创建几个视图。这个路由器将一个视图与一个URL进行关联。在本教程中,你将学习如何添加Vue Router库,将其集成到你的项目中,并创建动态生成的路由。你还将学习作为一个开发者可以使用的不同类型的路由。完成后,你将拥有一个可以使用各种方法导航的应用程序。
为了说明这些概念,你将创建一个显示机场信息的小应用程序。当用户点击一个机场卡时,该程序将导航到该机场的细节的动态视图。要做到这一点,程序将读取一个URL参数,并根据该参数过滤出数据。
前提条件
要完成本教程,你将需要。
- 在你的电脑上安装Node.js版本
10.6.0
或更高。要在macOS或Ubuntu 18.04上安装,请按照《如何在macOS上安装Node.js并创建本地开发环境》中的步骤,或按照《如何在Ubuntu 18.04上安装Node.js》中的《使用PPA安装》部分进行安装。 - 在你的机器上安装Vue CLI并生成一个新项目。在本教程中,创建应用程序时不要选择Vue Router。你将在本教程的第一步中手动安装它。这个项目的名称将是
airport-codes
,它将作为根目录。 - 你还需要有JavaScript、HTML和CSS的基本知识,你可以在我们的《如何用HTML建立网站》系列、《如何用CSS建立网站》系列和《如何用JavaScript编码》中找到。
第1步 – 设置示例应用程序
你要建立的学习Vue Router的应用程序将需要一些初始数据。在这一步中,你将创建并结构化这些数据,以便在本教程的后面部分可以被你的Vue应用程序访问。
要添加这个数据集,你需要创建一个data
目录,并创建一个名为airports.js
的JavaScript文件。如果你不在src
目录中,cd
先进入它。
cd src
复制代码
然后制作一个data
目录。
mkdir data
复制代码
现在创建一个data/airports.js
文件并在你的文本编辑器中打开它。
添加以下内容,为你的应用程序创建数据。
airport-codes/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' ]
}
}
]
复制代码
这个数据是一个对象 数组,由美国的几个机场组成。在这个应用程序中,你要遍历这些数据,生成由name
,abbreviation
,city
, 和state
属性组成的卡片。当用户点击一个卡片时,你将用Vue Router把他们送到一个动态视图,并从这些属性中读取。从那里,你将创建一个嵌套路由,以显示存储在destination
属性中的信息。
保存并退出该文件。
接下来,在一个名为views
的目录内创建一个Home.vue
组件。你可以通过打开你的终端并使用mkdir
和touch
命令来创建这个目录和组件。
运行下面的命令来创建这个目录。
mkdir views
复制代码
然后创建Home.vue
文件。
touch views/Home.vue
复制代码
这个Home.vue
组件将充当这个应用程序的主页。在其中,你将利用v-for
指令来遍历airports.js
数据集,并在卡片中显示每个机场。
添加以下代码到Home.vue
。
airport-codes/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
组件中,你正在遍历一个机场的集合,每个机场都被分配了一个CSS类:airport
。这个CSS为生成的HTML添加了一些样式,通过制作边框使每个机场具有卡片的外观。:first-child
和:last-child
是_伪_选择器,对HTML中第一个和最后一个p
标签应用不同的样式,其中div
的类别为airport
。
保存并关闭该文件。
现在你已经创建了这个初始视图和本地数据集,你将在下一步安装Vue Router。
第2步 – 安装Vue Router
你有几种方法可以安装Vue Router。如果你正在用Vue CLI从头开始创建一个新项目,你可以在提示中选择Vue Router;然后Vue CLI将为你安装和配置它。然而,在本教程中,我们假设你在CLI设置中没有选择Vue Router选项。你将通过npm安装Vue Router。
要安装Vue Router,首先从src
目录移回你的项目根目录。
cd ..
复制代码
然后在你的项目根目录下的终端窗口中运行下面的程序。
npm i vue-router@next
复制代码
你可能注意到这个命令中的@next
。因为这个项目使用的是Vue 3和Composition API,你在告诉npm下载这个库的最新实验版本。如果你想了解更多关于当前版本的信息,请查看GitHub上的Vue Router发布页面。
这将从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 Router库。实际上,你不需要为了创建路由而访问这个库中的一切。你可以选择取消结构或只导入你需要的东西,以尽量减少包的大小。在这种情况下,你需要两个来自vue-router
的函数:createWebHistory
和createRouter
。这些函数分别创建了一个用户可以回溯的历史,并为Vue构建了一个路由器对象。
添加以下代码到router/index.js
。
airport-codes/src/router/index.js
import { createWebHistory, createRouter } from "vue-router"
复制代码
接下来,添加以下突出显示的行来创建和导出你的路由器。
airport-code/src/router/index.js
import { createWebHistory, createRouter } from "vue-router"
const router = createRouter({
history: createWebHistory(),
})
export default router
复制代码
这个文件将导出一个路由器对象,该对象从createRouter
函数中返回。你传入的对象有两个属性:history
和routes
。history
属性包含从createWebHistory
生成的历史,routes
是一个对象数组。你将在本教程的后面添加routes
。
接下来,导入Home
视图并创建一个对象数组,将它们存储到一个名为routes
的const
。
airport-codes/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
:当在浏览器的URL栏中输入path
,就会被安装的组件。
现在你的routes
数组已经创建,你将需要把它添加到导出的router
对象中。
在history
的键/值对之后,添加routes
。这是在JavaScript中对routes: routes
的速记。
airport-codes/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
。然后添加以下突出显示的行。
airport-codes/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
文件。删除默认内容,用以下内容代替。
airport-codes/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
组件。值得注意的是,这并不是自动完成的。你将需要创建一个.vue
,并将其import
到你的路由器文件中去注册,如前面所详述的那样。
在你定义好所有其他路由之前,你可以创建一个default
路由。在本教程中,这个默认路由将作为一个404 – Not Found页面–在没有找到路由的情况下的一个退路。
首先,创建将作为404页面的视图。换到views
目录中。
cd views
复制代码
然后创建一个名为PageNotFound.vue
的文件。
touch PageNotFound.vue
复制代码
在你的文本编辑器中,打开你刚刚创建的这个PageNotFound.vue
文件。添加以下HTML代码,让视图有东西可以呈现。
airport-codes/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
文件,添加以下高亮代码。
airport-codes/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 Router for Vue 3使用一个自定义的RegEx。path
的值包含这个新的RegEx,它在告诉Vue为每个路由渲染PageNotFound.vue
,除非该路由已经被定义。这个路由中的catchAll
是指Vue Router中的一个动态段,而(.*)
是一个正则表达式,可以捕获任何字符串。
保存这个文件并在浏览器窗口中访问你的应用程序:localhost:8080/not-found
。你会发现PageNotFound.vue
组件在你的浏览器中呈现,如下图所示。
你可以自由地把这个URL改成其他任何东西;你会得到同样的结果。
在继续前进之前,为你的应用程序创建另一个路由。这个路由将是一个关于页面。
打开你选择的终端,在views
目录下创建文件。
touch About.vue
复制代码
在你的文本编辑器中,打开你刚刚创建的这个About.vue
文件。添加以下HTML以创建关于你的网站的更多信息。
airport-codes/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
。
airport-codes/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
文件中。
到目前为止,你的大多数路由都是_精确_路由。这意味着只有当URL片段与路由器的path
完全匹配时,组件才会挂载。然而,还有其他类型的路由,它们有自己的目的,可以动态地生成内容。在下一步,你将实现不同类型的路由,并学习何时使用其中一种。
第4步 – 创建有参数的路由
在这一点上,你已经创建了两个确切的路由和一个通往404页面的动态路由。但Vue Router的路由不止这些类型。你可以在Vue Router中使用以下路由。
- 动态路由。具有动态参数的路由,你的应用程序可以引用它来加载独特的数据。
- 命名路由。可以使用
name
属性访问的路由。此时创建的所有路由都有一个name
属性。 - 嵌套路由。与子程序相关联的路由。
- 静态或精确路由。具有静态
path
值的路由。
在本节中,您将创建一个显示单个机场信息的动态路由和一个用于机场目的地的嵌套路由。
动态航线
当您想重复使用一个视图,根据航线显示不同的数据时,动态航线是非常有用的。例如,如果你想创建一个视图,根据URL栏中的机场代码显示机场信息,你可以使用一个动态路由。在这个例子中,如果你访问的路线是localhost:8080/airport/cvg
,你的应用程序将显示代码为cvg
的机场的数据,即辛辛那提/北肯塔基国际机场。接下来,你将按照描述创建这个视图。
打开你的终端,用touch
命令创建一个新的.vue
文件。如果src
是你当前的工作目录,该命令将看起来像这样。
touch views/AirportDetail.vue
复制代码
创建完毕后,在你选择的文本编辑器中打开这个文件。继续创建你的template
和script
标签来设置这个组件。
airport-codes/src/views/AirportDetail.vue
<template>
<div>
</div>
</template>
<script>
export default {
setup() { }
}
</script>
复制代码
保存并关闭这个文件。
接下来,你需要在src/router/index.js
文件中注册这个视图。在你的文本编辑器中打开这个文件,然后添加以下高亮行。
airport-codes/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
组件。在这个组件中导入机场数据。
airport-codes/src/views/AirportDetail.vue
...
<script>
import airports from '@/data/airports.js'
export default {
setup() { }
}
</script>
复制代码
接下来,创建一个计算属性,如果该对象的abbreviation
属性与URL中的:code
参数匹配,则从数组中返回一个对象。在Vue 3中,你需要从vue
库中解除结构computed
。
airport-codes/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]
index语法来访问这个对象。route.params.code
是你访问在你的路由器文件中定义的参数的方式。为了访问路由的属性,你需要从vue-router
中导入一个名为useRoute
的函数。现在当访问一个路由时,你可以立即访问该路由的所有属性。你正在使用点符号来访问这个code
参数并检索其值。
在这一点上,如果URL中的代码与abbreviation
属性匹配,这个计算的属性将返回一个单一的机场对象。这意味着你可以访问一个机场的所有对象属性,并可以构建这个组件的template
。
继续在你的文本编辑器中编辑AirportDetail.vue
文件,构建出你的模板来显示机场的信息。
airport-codes/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 Router文档。
你可以把这种模式应用到你在本教程中构建的应用程序中。在本节中,你将添加一个视图来显示每个机场支持的目的地。
打开你的终端,在src
目录中,创建一个新文件,名称为AirportDestinations.vue
。
touch views/AirportDestinations.vue
复制代码
接下来,打开你的文本编辑器,添加以下内容。
airport-codes/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
参数相匹配的机场。
保存并关闭该文件。
要创建一个嵌套路由,你需要在src/router/index.js
文件中为你的路由对象添加children
属性。子(嵌套)路由对象包含与其父对象相同的属性。
打开router/index.js
,添加以下突出显示的行。
airport-codes/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
,并将其预置到子路由的path
。
打开你的浏览器窗口,并访问localhost:8080/airport/msp/destinations
。看起来没有任何东西与父代的AirportDetails.vue
不同。这是因为在使用嵌套路由时,你需要在父路由中包含<router-view />
组件。当访问子路由时,Vue将把子视图的内容注入到父视图中。
airport-codes/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 />
组件被全局导入。为了使用这个组件,你将把它添加到你的模板中并为它提供一个道具值。
在你的编辑器中打开views
目录中的Home.vue
组件。这个视图显示你在airports.js
文件中的每个机场。你可以用router-link
来替换包含的div
标签,以使每张卡片都能点击到它们各自的详细视图。
在Home.vue
中添加以下高亮行。
airport-codes/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
属性进行导航时,它是一对一的匹配。添加以下突出显示的片段。
airport-codes/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
,导航到不同的路线并不是最好的方法。事实上,一般认为最好的做法是使用命名路由进行导航。
要实现一个命名的路由,使用路由的name
,而不是path
。如果你参考src/router/index.js
,你会发现AirportDetail.vue
,其名称为AirportDetail
。
airport-codes/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
属性,其中包含一个代表你的参数的对象。
airport-codes/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为这个问题提供了一个解决方案,叫做_编程式导航_。
在本教程的早些时候,你创建了一个名为PageNotFound
的总括性路由。如果airport
计算属性在AirportDetail.vue
和AirportDestinations.vue
组件中返回undefined
,那么总是导航到该页面将是一个良好的用户体验。在本节中,你将实现这个功能。
在你的文本编辑器中,打开AirportDetail.vue
组件。为了实现这一点,检测airport.value
是否未定义。这个函数将在组件第一次安装时被调用,这意味着你将需要使用Vue的生命周期方法。
添加以下突出显示的行。
airport-codes/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主题页。