侧边栏壁纸
博主头像
xuesheng博主等级

分享web知识,学习就是取悦自己!

  • 累计撰写 118 篇文章
  • 累计创建 14 个标签
  • 累计收到 3 条评论

目 录CONTENT

文章目录

了解如何使用 Vue 3 + Vite 和 Pinia 创建、测试和部署单页应用

xuesheng
2022-02-13 / 0 评论 / 0 点赞 / 417 阅读 / 9,664 字 / 正在检测是否收录...
温馨提示:
本文最后更新于 2022-02-16,若内容或图片失效,请留言反馈。部分素材来自网络,若不小心影响到您的利益,请联系我们删除。

介绍

Vue.js创建于2014年,无疑是目前领先的前端框架之一,并且随着社区和生态系统的不断扩大,它的地位似乎在相当长的一段时间内是稳固的。几年前,我曾与 Vue 2 合作过一些项目,我发现这是一次愉快的经历。

我认为现在是时候用最新版本以及Vite和Pinia等较新的工具升级我的工具集了。

本指南将详细介绍使用 Vue 3 创建功能示例书店单页应用程序并使用 Vite 运行它的步骤。它还包括有关如何使用 Pinia(Vuex 后继者)添加状态管理和使用 Vue Router 进行路由的详细信息。

将涵盖的核心概念是:

  • 使用 Vite 创建 Vue 3 单页应用程序
  • 使用 Vue 路由器管理路由
  • 使用 Pinia 管理应用程序状态
  • 使用 Vite 运行、构建和部署应用程序
  • 编写和运行 Vue 组件测试
  • 使用 Nightwatch 编写和运行自动化的端到端测试.js

这可能看起来很多,但我认为完全有可能在不到20分钟的时间内完成所有这些工作。上面列出的一些主题可以扩展到它们自己的整个教程中,但现在我只介绍启动和运行所有内容所需的内容。

需要提到的最后一件事是,本教程中未介绍后端。虽然数据是使用浏览器Fetch API(XHR的后继者)加载的,但本身没有服务器端组件,因此可以轻松添加后端组件。

对于所有帐户和目的,我们将在此处构建的应用程序可以部署为静态网站。

如果您渴望直接开始编码,并且想立即进入其中,则可以通过以下方式启动并运行项目:

git clone https://github.com/beatfactor/middlemarch
npm install
npm run dev

或者在Github上fork项目:https://github.com/beatfactor/middlemarch

image.png

使用创建 vite 基架工具设置应用程序

我们将使用官方脚手架工具来设置项目结构,因此请确保您安装了NPM 6 +的Node 12 +。他们也支持 Yarn 和 PNPM 作为包管理器,但我们只介绍 NPM。create-vite

该工具还将为您创建项目文件夹,因此请确保先cd到父文件夹中:create-vite

cd /workspace

使用以下命令安装和初始化项目:Vite

npm init vite@latest

然后,系统将提示您输入项目名称并选择要使用的库。从列表中选择:vue

~/workspace % npm init vite@latest
npx: installed 6 in 1.051s
✔ Project name: … vue-bookstore
? Select a framework: › - Use arrow-keys. Return to submit.
    vanilla
❯   vue
    react
    preact
    lit
    svelte 

然后选择,因为我们不会使用TypeScript:vue

? Select a variant: › - Use arrow-keys. Return to submit.
❯   vue
    vue-ts

看到以下输出:

npx: installed 6 in 1.051s
✔ Project name: … vue-bookstore
✔ Select a framework: › vue
✔ Select a variant: › vue

Scaffolding project in /Users/andrei/workspace/vue-bookstore...

Done. Now run:

  cd vue-bookstore
  npm install
  npm run dev

按照上述说明操作后,我们将从Vite获得以下输出,告诉我们该应用程序正在运行:

 vite v2.7.7 dev server running at:

  > Local: http://localhost:3000/
  > Network: use `--host` to expose

  ready in 611ms.

让我们访问localhost:3000。欢迎页面如下所示:

image.png

使用 Vue 路由器添加路由,使用 Pinia 进行状态管理

让我们回顾一下该工具创建的项目的目录结构:create-vite

vue-bookstore/
 ├── public/
 |    ├── favicon.ico
 ├── src/
 |    ├── assets/
 |    |    └── logo.png
 |    ├── components/
 |    |    └── HelloWorld.vue
 |    ├── App.vue
 |    └── main.js
 ├─── package.json
 ├─── README.md
 └─── vite.config.js

在本指南的这一部分中,我们将向项目添加两个新的依赖项:和 。让我们继续从NPM安装它们。vue-routerpinia

Vue 路由器

vue-router是 Vue.js 的官方路由器。我们需要安装与 Vue 3 兼容的版本 router-4:

npm install vue-router@4 --save

Pinia

Pinia是 Vue 生态系统中出现的最新项目之一,它是 Vue.js 应用程序的新官方状态管理工具。它的api与(Vuex)非常相似,它被设计得更快,更轻量级。

您可以使用以下命令从 NPM 进行安装:pinia

npm install pinia --save

image.png

设置路由

如果您不熟悉单页应用程序中的路由或状态管理,请不要担心;这两个概念都非常容易理解,一旦你看到它是如何工作的,它们就会自我解释。

什么是单页应用程序?

单页应用程序只是一个 Web 应用程序,当您导航到其另一个子页面时,它不会重新加载页面。但是,浏览器的URL被修改了,就好像页面已被重新加载一样,这是使用HTML5 History API完成的。

在 Vite 中使用 Vue 组件

使用该工具创建的基架添加了一个非常基本的 Vue 组件,

create-vite src/components/HelloWorld.vuesrc/App.vue

还有另外两个重要文件:

  • index.html
  • src/main.js

该文件是浏览器导航到我们应用程序的页面时看到的内容,也是 Vue.js 应用程序的入口点。index.html ,main.js

这些文件的内容如下:

index.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <link rel="icon" href="/favicon.ico" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Vite App</title>
  </head>
  <body>
    <div id="app"></div>
    <script type="module" src="/src/main.js"></script>
  </body>
</html>

src/main.js

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

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

添加路由

现在是时候创建应用程序的主要路由了。在 Vue 中,每个路由都必须对应于一个组件。对于此应用程序,我们将考虑每个子页面的组件,如下所示:

  • Homepage主页 - 我们的书店主页
  • Cart购物车 - 购物车和结账页面
  • Sign-In登录 - 用户登录页面

对于基本的HTML和CSS,我也使用Bootstrap 5来处理UI下拉列表和表单等内容,但当然你可以使用任何你想要的UI库。

现在,我们将创建空的页面组件,以便设置路由。新的目录结构将如下所示:src

src/
  ├── components/
  |    └── TopNavbar.js
  ├── lib/
  |    ├── router.js   
  |    └── store.js
  ├── pages/
  |    ├── cart/
  |    |    ├── cart.css
  |    |    ├── cart.html
  |    |    └── Cart.vue
  |    ├── home/
  |    |    ├── home.css
  |    |    ├── home.html
  |    |    └── Home.vue
  |    ├── sign-in/
  |    |    ├── sign-in.css
  |    |    ├── sign-in.html
  |    |    └── SignIn.vue
  |    └── routes.js
  ├── App.vue
  └── main.js

我们添加了三个页面,每个页面都将保留非常基本。我们只需添加组件即可使导航在不重新加载页面的情况下正常工作。TobNavbar

为 添加以下内容,然后:

  • src/pages/cart/Cart.vue
  • src/pages/home/Home.vue
  • src/pages/sign-in/SignIn.vue
<script setup>
import TopNavbar from '../../components/TopNavbar.vue';
</script>

<template>
  <TopNavbar />
</template>
<style></style>

<script>
export default {
  components: {
    TopNavbar
  },

  computed: {},
  
  mounted() {
  },
  
  data() {
    return {
    };
  },
};
</script>

TopNavbar组件将仅包含导航链接。

<template>
  <router-link to="/">Home</router-link>
  <router-link to="/cart/">Cart</router-link>
  <router-link to="/sign-in/">Sign In</router-link>
</template>

pages/routes.js文件包含应用程序的所有路由声明。

import {createRouter} from 'vue-router'
import Homepage from './home/Home.vue';
import SignIn from './sign-in/SignIn.vue';
import Cart from './cart/Cart.vue';

const routes = [
  {
    path: '/',
    component: Homepage
  },

  {
    path: '/sign-in/',
    component: SignIn
  },

  {
    path: '/cart/',
    component: Cart
  },
]

export default function (history) {
  return createRouter({
    history,
    routes
  })
}

1) 创建路由器并将其添加到主 Vue 应用程序实例中, 在 :src/main.js

import { createApp } from 'vue'
import { createWebHistory } from 'vue-router'

import createRouter from './pages/routes.js'
import App from './App.vue'

const router = createRouter(createWebHistory())
const app = createApp(App)
app.use(router).mount('#app')

2) 添加组件:src/App.vue

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

重新运行,然后导航到启用路由的 Vue 3 应用程序。npm run devhttp://localhost:3000

image.png

使用 Pinia 设置状态管理

Pinia 是 Vue 核心团队.js一个新项目,现在是使用应用程序状态的推荐方法。如果你已经熟悉Vuex,那么习惯Pinia会很简单。事实上,Pinia api比Vuex稍微容易一些,也不那么冗长。

使用Pinia,在Vue 3应用程序中,有一个根store,然后是任意数量的单个store。对于我们的书店应用,我们将仅使用两个store:

  • 目录store:可用书籍的列表
  • 购物车store:用户想要订购的图书

创建Pinia

"pinia"是我们必须首先创建的根存储,并将其传递给 Vue 实例。

我们将在其中执行此操作,并将其更新为:src/main.js

import { createApp } from 'vue'
import { createWebHistory } from 'vue-router'
import { createPinia } from 'pinia'

import createRouter from './pages/routes.js'
import App from './App.vue'

const store = createPinia()
const router = createRouter(createWebHistory())
const app = createApp(App)

app.use(router).use(store).mount('#app')

下一步是创建单个目录和购物车store,并在组件中使用它们。

添加目录存储

创建Pinia store主要意味着两件事:

  • 定义store
  • 在一个或多个组件中使用存储

定义应用store

与 Vuex 一样,Pinia 存储包含状态和两种类型的方法:getteractions

关于store需要考虑的一些事项:

  • Getters是用于从状态中检索数据的同步函数
  • Actions也可以是异步的函数,用于更新状态
  • 被定义为返回初始状态的函数state

在里面创建目录store了:src/stores/catalog.js

import { defineStore } from 'pinia'

export const useCatalog = defineStore('catalog-store', {
  state: () => {
    return {
      newArrivals: [],
      fetching: false
    }
  },

  getters: {
    results(state) {
      return state.newArrivals;
    },

    isFetching(state) {
      return state.fetching;
    }
  },

  actions: {
    async fetchNewArrivals() {
      this.fetching = true;
      const response = await fetch('/data/new-arrivals.json');
      try {
        const result = await response.json();
        this.newArrivals = result.books;
      } catch (err) {
        this.newArrivals = [];
        console.error('Error loading new arrivals:', err);
        return err;
      }

      this.fetching = false;
    }
  }
})

查看上面的源代码,您会注意到我们有两个 getter 和一个action。我们不是真正的后端,而是有一个json文件,其中包含一些我们将用作目录的书籍。/data/new-arrivals.json

我们的 getter 不会对数据做任何特殊的事情,所以他们有点不必要,但我认为展示如何定义它们仍然很好。

在template中使用"store"

将上述定义链接到模板也非常简单。

让我们创建一个调用的新组件,我们将在其中使用它作为页面组件。NewArrivals
src/components/NewArrivals.vueHome.vue

<script setup>
import {useCatalog} from '../../store/catalog.js'
</script>

<template>

</template>

<style scoped></style>
<script>
import { mapState, mapActions } from 'pinia'

export default {
  computed: {
    ...mapState(useCatalog, {newArrivals: 'results'})
  },

  methods: {
    ...mapActions(useCatalog, ['fetchNewArrivals']),

    addToCart() {
      // we'll populate this later
    }
  },

  created() {
    // when the template is created, we call this action
    this.fetchNewArrivals();
  }
};
</script>

组件变为:Home.vue

<script setup>
import TopNavbar from '../../components/TopNavbar.vue';
import NewArrivals from '../../components/NewArrivals.vue';
</script>

<template>
  <TopNavbar />
  <NewArrivals />
</template>

<style></style>

<script>
export default {
  components: {
    TopNavbar,
    NewArrivals
  },
  computed: {},
  mounted() {},
  data() {
    return {};
  },
};
</script>

下面是存储和组件如何在应用程序中协同工作的图:

image.png

我还为购物车编写了一个store和一个components,但我不会将其包含在教程中,因为机制是相似的,您可以检查存储库中的源代码,该源代码将所有内容添加到一起,甚至是某些样式。

image.png

测试 Vue.js 组件

组件测试是一种 UI 测试类型,其中组件在隔离状态下呈现,而不使用其他应用组件,以验证其功能。它通常是一种测试策略,发生在端到端测试步骤之前,我们将在下一节中详细阐述。

我们需要安装 Vue TestUtils 项目,这是 Vue 的官方单元测试库.js我们需要一个面向 Vue 3 的项目。您可以使用以下命令从 NPM 安装它:

npm install @vue/test-utils@next --save-dev

安装 Nightwatch.js 和 ChromeDriver

我们将使用 Nightwatch.js 进行组件测试和端到端测试。Nightwatch已经是Vue.js团队推荐的测试框架之一,并且与Vue同时发布。

vite-plugin-nightwatch获得了对Vue组件测试的支持。我们将继续安装Nightwatch(版本2.0):

npm install nightwatch --save-dev

我们还需要前面提到的:vite-plugin-nightwatch

npm install vite-plugin-nightwatch --save-dev

Nightwatch使用W3C WebDriver API执行浏览器自动化任务,我们还需要安装NPM包,因为我们将使用Chrome来运行我们的测试。

npm install chromedriver --save-dev

测试<组件

其中包括一个测试渲染器页面,Nightwatch已经包含运行我们组件的初始测试所需的一切。vite-plugin-nightwatch

创建一个文件夹,并在其中添加两个子文件夹:test

  • component- 这将举行组件测试
  • e2e- 这将举行端到端测试

我们还需要一个配置文件nightwatch.conf.js,但是我们可以直接运行Nightwatch,并且将自动为我们创建配置文件。只需确保也安装了(当然还有Chrome浏览器)。

确保当前工作目录是项目根目录,然后只需运行与Nightwatch捆绑在一起的示例测试即可。我们将选择测试运行duckDuckGo

npx nightwatch examples/tests/duckDuckGo.js

项目结构现在应如下所示:

vue-bookstore/
 ├── public/
 |    ├── data/
 |    └── favicon.ico
 ├── src/
 ├── ...
 |    └── main.js
 ├── test/
 |    ├── component/
 |    └── e2e/
 ├─── nightwatch.conf.js
 ├─── package.json
 ├─── README.md
 └─── vite.config.js

我们将继续创建一个名为 inside 的新文件。在其中,我们只需添加一个基本测试,该测试将挂载组件并检查是否可以在页面中找到返回的元素(即组件已挂载)。

newArrivalsTest.js
test/component

describe('New Arrivals Component Test', function() {

  it('checks if the component has been mounted', async (browser) => {
    const component = await browser.mountVueComponent('/src/components/new-arrivals/NewArrivals.vue', {
      plugins: {
        router: '/src/lib/router.js'
      }
	});
    
    expect(component).to.be.present; 
  });
});

Nightwatch使用与Mocha相同的语法。如果您已经熟悉Mocha,您甚至可以将其用作测试运行程序,但我们现在不打算这样做。describe()

我们将使用Chrome运行Nightwatch,如下所示:

npx nightwatch test/component/newArrivalsTest.js --env chrome

将打开 Chrome 浏览器并呈现组件,然后执行测试。如果您不喜欢在测试期间看到浏览器窗口弹出,则可以传递参数,如下所示:--headless

npx nightwatch test/component/newArrivalsTest.js --env chrome --headless

测试输出应如下所示:

[New Arrivals Component Test] Test Suite
──────────────────────────────────────────────────────────────
ℹ Connected to ChromeDriver on port 9515 (652ms).
  Using: chrome (97.0.4692.99) on MAC OS X.


  Running tests the component:
──────────────────────────────────────────────────────────────
  ✔ Expected element <web element{e53f9b1e-11d3-4dc4-8728-4d3cd077343e}> to be present (1ms)

OK. 1 assertions passed. (781ms)

可以查阅 Nightwatch 跑步者提供的所有 CLI 选项,方法是转到文档页面或运行:

npx nightwatch --help
0

评论区