五、Vue CLI 3 和路由

在上一章中,我们了解了如何在 Vue 中使用一些测试套件,如 Jest 和 Cypress。在本章中,我们将介绍如何使用 vue 路由,并将其与 vue CLI 3 一起使用。我们将研究一些实际任务,例如延迟加载组件。我们将介绍如何使用 Vue add 命令添加 Vue 路由,以及为什么这不是最好的策略,以及采取哪些措施来缓解这一问题。如果您想构建更大、更复杂的应用,了解 Vue 中的路由是非常有益的。以下是本章涵盖的主题列表:

  • 使用 Vue 路由和 vuex 添加新的 Vue 项目
  • 通过 VS 代码的命令行配置预设选项
  • 了解 vue 路由路由
  • 使用命名路由
  • 添加动态路由
  • 从 Vue 实例中的“方法”选项导航到路由
  • 使用嵌套(子)管线
  • 延迟加载路径

我们将从添加一个新项目开始。

使用 Vue 路由和 vuex 添加新的 Vue 项目

让我们首先在文件系统中创建一个新文件夹。我们把这个文件夹称为vueclichapter5

  1. 从 Windows 资源管理器中打开vueclichapter5文件夹,右键单击vueclichapter5文件夹中空白处的任意位置,然后单击 Git Bash here 命令。

  2. Git Bash 打开后,键入code .并按回车键。这将打开一个全新的 VS 代码实例,其中除了欢迎选项卡之外没有其他文件或选项卡。

  3. 接下来,我们将从 VS Code 的集成终端添加一个新的 Vue 项目。要访问此终端,请单击 VS 代码窗口(使其处于焦点),然后按以下快捷键:Ctrl+`

We've already mentioned the Ctrl backtick shortcut earlier in the book. As a reminder, the ` character can be found when you press the key above the Tab key on your keyboard. 

使用Ctrl+`键盘快捷键将打开 VS 代码内的终端。

  1. 接下来,我们将使用一个点运行vue create命令,如下所示:
vue create .

这样做将在现有文件夹中生成一个 Vue 项目,也就是说,它不会为我们的新 Vue 项目生成子文件夹,如下所示:

Figure 5.1: Generating a project in the current directory from VS Code's Terminal 

  1. Y键确认我们将在当前目录中生成项目。

通过 VS 代码的命令行配置预设选项

接下来,我们将通过按一次向下箭头键,然后按回车键来选择手动选择功能选项,如下图所示:

Figure 5.2: Generating a project in the current directory from VS Code's Terminal 

添加 vue 路由和 vuex

接下来,我们将使用向下箭头键和空格键选择 Router 和 Vuex 作为项目中使用的附加功能,如以下屏幕截图所示:

Figure 5.3: Adding the vue-router and vuex plugins to our project

提示将询问我们是否要使用路由的历史模式。

我们现在不想使用它,所以我们只需键入n并按输入

在本章后面,我们将讨论 History 模式的作用以及它是如何工作的。

添加 ESLint 和 Prettier

另一个提示询问我们的 linter 或 formatter 首选项。我们将使用 ESLint 和 Prettier,如下所示:

Figure 5.4: Choosing ESLint and Prettier as or linter / formatter configuration

完成配置

最后,我们将接受默认的 Lint on save 特性,并选择将 Babel、postsss、ESLint 等的配置放在专用配置文件中,如下所示:

Figure 5.5: Choosing to save configs in dedicated config files

最后,Vue CLI 将询问我们是否希望将其保存为预设,以供将来的项目使用。我们暂时对此说不。

为我们的新项目安装所有插件

最后,Vue CLI 将按如下方式安装所有插件:

Figure 5.6: Vue CLI installing our project's plugins

完成此安装后,我们将安装一个工作的 Vue 项目,并安装 Vue 路由和 vuex、ESLint 和 Prettier,并准备好使用。

从 Vue CLI UI 为我们的项目提供服务

一旦安装了我们的项目,我们就可以使用npm run serve命令来运行它。但是,我们将使用 Vue CLI UI 进行此操作,因此让我们使用vue ui运行它,如下所示:

Figure 5.7: Serving our project via vue UI command from VS Code command line

正如预期的那样,我们的 Vue CLI UI 将在浏览器窗口http://localhost:8000/dashboard中自动打开。此时,旧项目可能会加载到仪表板中,因此我们需要单击主页图标并导入新的vueclichapter5项目。

Note that we could have installed a new app using the Vue CLI UI from the very beginning, but it is interesting to know that you can switch between the command line and the UI without issues.

加载项目后,我们可以单击插件链接查看已安装的插件。请注意,没有添加 vue 路由和添加 vuex 按钮。它们不存在,因为我们已经安装了它们。

从 UI 运行服务任务

最后,我们将单击任务图标打开可用任务的列表,然后单击服务任务来编译和服务我们的项目。与之前一样,运行任务面板将显示在仪表板的右侧,如下所示:

Figure 5.8: Run task for the npm run serve script 

在前面的屏幕截图上,我们可以看到 serve task 屏幕的放大部分。单击“运行任务”按钮将开始构建应用,我们将在 Windows 开始栏上收到通知,我们的应用已成功构建。查看可用选项卡,我们可以看到当前视图显示了服务任务的仪表板。单击当前活动的服务任务仪表板按钮左侧的输出按钮,将向我们显示日志信息,如下所示:

  App running at:
  - Local: http://localhost:8082/
  - Network: http://192.168.1.70:8082/

  Note that the development build is not optimized.
  To create a production build, run npm run build.

当然,vue-cli-service为我们的 Vue 应用提供服务的具体端口将取决于其他端口已在使用的端口。要在浏览器中打开我们正在运行的 Vue 应用,现在只需单击输出日志中列出的LocalNetworkURL。

在 vue 路由中使用路由

在接下来的部分中,我们将研究 vue 路由中的路由如何工作,以及如何使用它们添加页面和路由。我们将首先检查现有路由,然后添加其他路由及其相应组件。

检查两个默认路由

这将打开一个熟悉的带有 Vue 徽标的启动项目,只需添加一点:顶部有一个指向“关于”页面的链接,如以下屏幕截图所示:

Figure 5.9: Default navigation of the project with vue-router installed 

如果单击“关于”链接,您将看到另一个页面,该页面有一个h1标记,其中包含以下文本:

This is an about page

Notice that the route to the About page has a pound sign in front of the page name. In our example app, it looks like this: http://localhost:8082/#/about. How do we get rid of the pound sign? In other words, how to we set the address to http://localhost:8082/about?

The answer is simple, we just need to set up our server to always return the index.html page, and then we're going to add another setting, the mode setting, for the vue-router, such as the following: mode: 'history'

You need to add the preceding code right under the export default new Router({ line in router.js. Doing this will get rid of the pound symbol.

接下来,我们将检查随 vue 路由和 vuex 预装的项目内容。

检查项目文件

返回 VS 代码并查看项目结构。你会看到一些与我们以前的不同之处。以下是我们src文件夹的内容:

Figure 5.10: The contents of the src folder with vue-router and vuex pre-installed 

src文件夹中,我们可以看到一个以前从未见过的文件夹:views文件夹,其中包含两个视图文件:Home.vueAbout.vue。在我们项目的根目录中,我们还可以看到一些附加文件:router.jsstore.js.browserslistrceslintrc.jspostcss.config.jsREADME.md

router.js文件是 vue 路由用来在我们的应用中设置路径的文件。routes数组是一个对象数组:一个对象对应一条路由。由于默认安装中有两条路由,routes数组中有两个对象。store.js文件是 vuex 用来跟踪我们应用的状态、变化和动作的文件;这些都被称为vuex 商店README.md文件列出了与我们的应用一起使用的常见 npm 命令,项目根目录下的其他文件是配置文件;在我们通过 Vue CLI 3 的过程中,这一约定是意料之中的。

main.js 的内容

正如我们之前看到的,我们的src文件夹中的main.js文件导入了以下所有依赖项:

  • 来自node_modules的 Vue 库
  • 根组件App.vue
  • 用于设置 vue 路由路由的路由文件
  • 用于设置 vuex 存储的存储文件

App.vue 文件和路由链接导航

通过检查根组件App.vue的内容,我们可以看到该文件看起来与以前不同:没有script节!

此外,App.vue内的模板标签包含所谓的导航组件。每个导航项都包含在router-link标签内。

为什么不使用锚定标记而不是router-link标记?因为锚定标记将继续并发送服务器请求。使用router-link标记可以避免这种行为。

如果我们检查dist文件夹中已编译的 HTML 代码,我们将看到捆绑的 HTML 确实最终成为锚定标记,如以下已编译的生产代码所示:

<div id="nav">
    <a href="#/" class="router-link-active">Home</a> |
    <a href="#/about" class="router-link-exact-active router-link-active">About</a>
</div>

回到view文件夹中的Home.vueAbout.vue文件,我们还可以看到router-view标签(在div下方,带有navid。这就是实际呈现的Home viewAbout view。将被渲染的组件将由使用to属性映射的任何组件确定。

呈现 Vue 实例并将其装入#应用

最后,调用 Vue 的一个新实例,并以 options 对象的形式传递一个参数。对象接收以下键值对:router: routerstore: storerender: h => h(App)

用 ES5 代码编写,该代码如下所示:

new Vue({
    router: router,
    store: store,
    render: function render(h) {
        return h(App);
    }
}).$mount("#app");

幸运的是,我们的main.js文件是用更现代的语法编写的,所以当所有这些东西放在一起时,看起来如下所示:

import Vue from "vue";
import App from "./App.vue";
import router from "./router";
import store from "./store";

Vue.config.productionTip = false;

new Vue({
  router,
  store,
  render: h => h(App)
}).$mount("#app");

将我们的应用和不同的部分结合起来,并将它们安装好。最后,我们的 Vue 应用将安装到div中,应用的id位于我们的./public/index.html中。

您可能会注意到,我们当前应用的目录不包含dist文件夹。正如我们在第 2 章中所了解的,Vue CLI 3中的 Webpack,dist 文件夹是 Webpack 构建我们网站的产物。接下来,让我们在 Vue CLI 3 UI 中运行构建任务,以查看正在创建和提供的dist文件夹。

从 UI 运行构建任务

要从 Vue CLI 3 UI 运行生成任务,我们只需转到http://localhost:8000/tasks/,然后单击生成任务,然后单击运行任务按钮。

我们运行的生成任务的“输出”选项卡将注销以下信息:

  File Size Gzipped

  dist\js\chunk-vendors.1030118d.js 116.48 KiB 40.51 KiB
  dist\js\app.51b1d496.js 5.97 KiB 2.23 KiB
  dist\js\about.d288b4f1.js 0.44 KiB 0.31 KiB
  dist\css\app.08e7a232.css 0.42 KiB 0.26 KiB

  Images and other types of assets omitted.

 DONE Build complete. The dist directory is ready to be deployed.
 INFO Check out deployment instructions at https://cli.vuejs.org/guide/deployment.html

./dist/js/文件夹中的这些不同 JavaScript 文件是什么?它们是 webpack 将我们的资产从 Vue 应用的单文件组件、路由和商店捆绑到部署就绪捆绑包中的结果。这些捆绑包现在被添加到我们的dist文件夹中的已编译和缩小的index.html页面中,因此它们最终会出现在我们的生产就绪网页上。

最后,让我们看看我们更新的应用。为此,我们将单击服务任务,并通过单击停止任务按钮停止任务。

从 UI 以生产模式为应用提供服务

要在生产模式下为应用提供服务,我们需要在选择服务任务的情况下单击运行任务面板内的参数按钮。

单击“参数”按钮后,我们将看到以下对话框:

Figure 5.11: Specifying the env mode in serve task's parameters dialog inside the Vue CLI 3 UI

在指定环境模式设置中,单击下拉菜单并选择生产。保存更改,您将再次看到服务任务仪表板。现在,单击 RunTask 按钮。最后,为了确保一切正常,请将浏览器指向 Vue 应用所使用的端口。在本例中,正确的地址是http://localhost:8082/。接下来,单击“关于”链接

*返回 VS 代码,将About.vue页面的h1标记更改为以下内容:

<h1>This is an about page. HMR rocks!</h1>

保存文件并查看关于获取 HMR 更新的页面。

使用管线的一些基础知识

虽然本书是关于 Vue CLI 3 的,但我们将借此机会快速列出 Vue 路由的一些功能。这绝不是一个广泛的列表:它只是您需要了解的某些功能的快速概述:

  • 使用命名路由
  • 添加动态路由
  • 从 Vue 实例中的“方法”选项导航到路由
  • 使用嵌套(子)管线
  • 延迟加载路径

我们首先要了解,router-view标记需要嵌套。

路由视图标记需要嵌套

在开始之前,让我们看一下App.vue模板标记,如下所示:

<template>
  <div id="app">
    <div id="nav">
      <router-link to="/">Home</router-link> |
      <router-link :to="{ name: 'about' }">About</router-link> | 
      <router-link :to="{ name: 'cars' }">Cars</router-link>
    </div>
    <router-view />
  </div>
</template>

注意,router-view元素(从底部开始的第三行)被包装在父div标记中,然后父div标记被包装在template标记中。这很重要,因为您不能将router-view标记作为template标记的直接子级。换句话说,以下情况是不可能的:

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

既然我们知道这种方法行不通,我们可以继续讨论命名路由。

使用命名路由

要使用命名路由,只需将对象传递给router-link标记内的to道具,如下所示:

<router-link :to="{ name: 'about' }">About</router-link>

注意to道具前面的:。每当我们想要添加命名路由时,就会添加此:

在我们传递给to道具的对象内有name键,vue 路由将检查router.js内的routes阵列。它将查找具有指定值的名称键的对象,如果找到该对象,它将重新将其路由到特定的视图组件。

通过触发 Vue 实例的方法导航到路由

Vue 中的每个组件都是独立的 Vue 实例。我们将在HelloWorld.vue组件中工作。要从HelloWorld.vuemethods选项导航到路线,您可以在组件的scripts部分使用以下代码:

methods: {
 goToAboutPage(){ 
 this.$router.push({path: '/About'}) 
 },
}

为了实现这一点,我们需要添加一个v-*指令,以确定具有前面代码的方法何时被触发。因此,仍然在HelloWorld.vue内,将template标记更新为以下内容:

<template>
 <!-- code skipped for brevity -->
 <p v-on:mouseover="goToAboutPage" 
    style="color: red; font-size: 50px; background: gray; max-width: 500px; margin: 0 auto">
    Hover to see the About Page
 </p>
 <!-- code skipped for brevity -->
</template>

显然,前面的template标记不完整。我们关注的是重要的部分:p标记,文本颜色为红色,字体大小为50像素。在屏幕上你不会错过的!您可以在vuecli3chapter5/HelloWorld.vue中找到这行代码,从第 4 行开始。

当您将鼠标悬停在上一段上时,Vue 会立即将您转到“关于”页面。

现在,让我们将主页上的相同功能添加到“关于”页面。因此,在“关于”页面上,您可以将鼠标悬停在突出的悬停上以查看主页链接,该链接将带您返回主页。

为了让事情不那么紧张,我们还可以使用好的老式普通浏览器外观功能:setTimeout。以下是About.vue文件的更新代码:

<template>
  <div class="about">
    <h1>This is an about page. HMR rocks!</h1>
    <p v-on:mouseover="goToHomePageSlowly" class="go">Hover to see the Home Page</p>
  </div>
</template>
<script>
export default {
  name: "About",
  props: {
    msg: String
  },
  methods: {
      goToHomePage(){ 
        this.$router.push({path: '/'}) 
      },
      goToHomePageSlowly(){
        setTimeout(() => this.goToHomePage(), 1000);
      }
  }
};
</script>
<style>
.go {
  color: purple; 
  font-size: 50px; 
  cursor: pointer;
  max-width: 500px;
  margin: 0 auto;
  background: #fabdab;
}
</style>

在前面的代码中我们在做什么?我们只是在methods选项中添加另一个方法。我们将这个新方法命名为:goToHomePageSlowly。然后,我们在 about 组件的模板标记中调用这个方法

goToHomePagesSlowlysetTimeout外观功能用于浏览器的setTimeout功能。setTimeout函数以1000毫秒的延迟调用我们的goToHomePage函数,一旦运行,它将使用$router返回主页。

接下来,我们将讨论嵌套路由。

使用嵌套管线

在开始使用嵌套路线之前,我们将在src/views文件夹中添加 Cars 组件,如下所示:

<template>
  <div class="home">
    <HelloCars msg="Welcome to Your Cars" />
    <router-view></router-view>
  </div>
</template>

<script>
// @ is an alias to /src
import HelloCars from "@/components/HelloCars.vue";

export default {
  name: "cars",
  components: {
    HelloCars
  }
};
</script>

要使用嵌套路由,需要在router.js内部的path对象中添加children数组,如下例所示:

routes: [
    {...},
    {...},
    {
      path: "/cars",
      name: "cars",
      component: Cars, 
      children: [
          { path: '/cars', component: CarsHome },
          { path: '/cars/cars-new', component: CarsNew },
          { path: '/cars/cars-used', component: CarsOld }
      ]
    }
]

这些子组件中的每一个都需要路由。由于它们是嵌套管线,因此需要从各自的父组件调用它们。在我们的例子中,这是HelloCars组件。我们将使用以下代码在components文件夹中添加HelloCars.vue组件:

<template>
 <div class="hello">
 <h1>{{ msg }}</h1>
 </div>
</template>

<script>
export default {
 name: "HelloCars",
 props: {
 msg: String
 }
};
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
* {
 margin: 0 auto;
}
</style>

现在我们所要做的就是添加我们的父HelloCars.vue组件将调用的其他子组件

/cars路由的默认子组件是CarsHome.vue组件,如下所示:

<template>
  <div class="home">
    <div>
        This is Cars home
        <ul>
            <li><router-link to="/cars/cars-new">See new cars</router-link></li>
            <li><router-link to="/cars/cars-used">See old cars</router-link></li>
        </ul>
    </div>
  </div>
</template>

<style>
ul li { list-style-type: none }
</style>

如前所述,HelloCars.vue组件的子组件之一是CarsNew.vue组件,如下所示:

<template>
  <div>
    <div>
        This is Cars New
        <ul>
            <li><router-link to="/cars">Back to cars home</router-link></li>
        </ul> 
    </div>
  </div>
</template>

HelloCars.vue组件的另一个子组件是CarsOld.vue,如下所示:

<template>
  <div>
    <div>
        This is Cars Old
        <ul>
            <li><router-link to="/cars">Back to cars home</router-link></li>
        </ul> 
    </div>
  </div>
</template>

现在我们了解了嵌套路由是如何工作的,我们将转移注意力,简要讨论延迟加载路由。

延迟加载路径

有时,webpack 生成的 JavaScript 包太大。这将减慢加载 web 应用所需的时间,这当然是不可取的

为了避免这种情况,我们可以回想一下 vue 路由的工作原理:每个路由都是一个单独的 vue 组件。

我们之前已经看到,webpack 在捆绑我们的 Vue 应用时会产生。这种行为可以对我们有利,因此每个组件都被捆绑到一个单独的块中。这是通过 webpack 中 Vue 的异步组件代码拆分实现的。

使用动态路由

什么是动态路线?让我们想象一个购物平台,其中任何待售商品的 URL 结构都列在如下链接中:

https://example.com/items/:id

:id部分被称为动态段。要处理动态段,您首先需要将它们列在router.js中的路由对象数组中,就像任何其他路由一样,如下所示:

routes: [
    {...},
    {...},
    {
        path: "/item/:id",
        name: "item",
        component: Item
    }
]

显然,在前面的代码中,我们使用三个点来节省空间。

回到Item.vue视图组件的模板标记中,我们需要添加以下语法:

<template>
    <article>
        <h1>Shopping item: {{ $route.params.id }}</h1>
    </article>
</template>

我们活动路由的状态存储在$route

至少可以单独编写一整章关于动态路由的内容,因此目前,我们需要通过查看 Vue 实例中methods选项的触发路由来继续讨论。

至此,我们结束本章。

总结

在本章中,我们介绍了如何使用 Vue 路由和 vuex 添加新的 Vue 项目。我们还通过 VS 代码的命令行配置了预设选项。我们讨论了 vue 路由路由,并了解了如何使用命名路由、添加动态路由、从 vue 实例中的“方法”选项导航到路由,以及如何使用嵌套(子)路由。

在下一章中,我们将了解如何在 Vue CLI 3 中使用 ESLint 和 Prettier。*