如何使用 Vue 单文件组件创建可重用代码块

_ 作者选择了 开源精神疾病 作为 写给捐赠 计划的一部分的捐赠。

介绍

在使用 [Vue.js] (https://vuejs.org/] 创建网络应用程序时,将您的应用程序构建在小而模块化的代码块中是一种最佳做法. 这不仅保持了应用程序部分的焦点,也使得应用程序随着复杂性的增加而更容易更新. 由于由Vue CLI生成的应用程序需要一个构建步骤,所以您可以访问_Single-File组件_(SFC),将模块化引入您的应用程序. SFCs拥有'.vue'扩展并包含一个HTML QTemplate , QQscript 和 QQstyle 标记,可以在其他组件中执行.

SFCs为开发人员提供了一种方式来为每个组件创建自己的 HTML标签,然后在他们的应用程序中使用它们。就像<p>HTML标签在浏览器中渲染一个段落,并保持非渲染的功能一样,组件标签将渲染SFC在Vue模板中的任何地方。

在本教程中,您将创建一个SFC,并使用props来传输数据,并将slots用于在标签之间注入内容。

前提条件

  • 节点.js版本`14.16.0'或更多安装在您的计算机上。 要在 macOS 或 Ubuntu 20. 04 上安装此功能,请遵循 [如何在 macOS (https://andsky.com/tech/tutorials/how-to-install-node-js-and-create-a-local-development-environment-on-macos) 上安装节点并创建本地开发环境 或使用 [如何在 Ubuntu 20. 04 上安装节点.js (https://andsky.com/tech/tutorials/how-to-install-node-js-on-ubuntu-20-04 的 部分 PPA 中的** 。
  • [Vue CLI已安装] (https://andsky.com/tech/tutorials/how-to-generate-a-vue-js-single-page-app-with-vue-create)在您的机器上,并生成了一个新项目. 由于此教程使用 Vue 3 组成 API, 请在生成应用程序时确保您选择3. x (Preview) 选项 。 本项目的名称将是 " sfc-project " ,它将作为根目录。
  • 联合国 您还需要JavaScript, HTML, CSS 的基本知识, 您可以在 [How To Build a website With HTML (https://www.digitalocean.com/community/tutorial_series/how-to-build-a-website-with-html) 系列, [How To Build a website With CSS (https://www.digitalocean.com/community/tutorial_series/how-to-build-a-website-with-css) 系列, 以及 [How To Code in JavaScript (https://www.digitalocean.com/community/tutorial_series/how-to-code-in-javascript) 中找到这些知识 。 .

步骤1 - 设置项目

在本教程中,您将创建一个机场卡组件,该组件将显示数个机场及其代码在一系列的卡片中。 遵循前提部分后,您将有一个名为sfc-project的新Vue项目。 在本节中,您将导入数据到这个生成的应用程序。

一旦项目生成,打开您的终端和cd或更改目录到根文件夹src:

1cd sfc-project/src

从那里,使用mkdir命令创建一个名为data的新目录,然后使用touch命令创建一个名为us-airports.js的新文件:

1mkdir data
2touch data/us-airports.js

在您所选择的文本编辑器中,打开这个新的JavaScript文件并添加以下本地数据:

 1[label sfc-project/data/us-airports.js]
 2export default [
 3  {
 4    name: 'Cincinnati/Northern Kentucky International Airport',
 5    abbreviation: 'CVG',
 6    city: 'Hebron',
 7    state: 'KY'
 8  },
 9  {
10    name: 'Seattle-Tacoma International Airport',
11    abbreviation: 'SEA',
12    city: 'Seattle',
13    state: 'WA'
14  },
15  {
16    name: 'Minneapolis-Saint Paul International Airport',
17    abbreviation: 'MSP',
18    city: 'Bloomington',
19    state: 'MN'
20  }
21]

這個數據是 arrayobjects 由幾個機場在美國組成. 這將會在一個單一檔案組成部分後來在教程。

保存和退出文件。

接下来,您将创建另一组机场数据,这些数据将包括欧洲机场,使用触摸命令创建一个名为eu-airports.js的新JavaScript文件:

1touch data/eu-airports.js

然后打开文件并添加以下数据:

 1[label sfc-project/data/eu-airports.js]
 2export default [
 3  {
 4    name: 'Paris-Charles de Gaulle Airport',
 5    abbreviation: 'CDG',
 6    city: 'Paris',
 7    state: 'Ile de France'
 8  },
 9  {
10    name: 'Flughafen München',
11    abbreviation: 'MUC',
12    city: 'Munich',
13    state: 'Bavaria'
14  },
15  {
16    name: 'Fiumicino "Leonardo da Vinci" International Airport',
17    abbreviation: 'FCO',
18    city: 'Rome',
19    state: 'Lazio'
20  }
21]

此数据集适用于法国、德国和意大利的欧洲机场。

保存和退出文件。

接下来,在 root 目录中,在终端中运行以下命令,在本地开发服务器上启动 Vue CLI 应用程序:

1npm run serve

这将打开您的浏览器中的应用程序在localhost:8080

请访问您的浏览器中的地址,您将看到以下启动屏幕:

Vue default template page

接下来,开始一个新的终端,并在你的src文件夹中打开你的App.vue文件. 在这个文件中,删除imgHelloWorld标签在<template>components部分和import声明在<script>

 1[label sfc-project/src/App.vue]
 2<template>
 3
 4</template>
 5
 6<script>
 7export default {
 8  name: 'App',
 9}
10</script>
11
12<style>
13#app {
14  font-family: Avenir, Helvetica, Arial, sans-serif;
15  -webkit-font-smoothing: antialiased;
16  -moz-osx-font-smoothing: grayscale;
17  text-align: center;
18  color: #2c3e50;
19  margin-top: 60px;
20}
21</style>

在此之后,导入您之前创建的 us-airports.js 文件. 为了使此数据具有反应性,因此您可以在 <template> 中使用它,您需要从 vue 中导入 ref 函数

添加以下突出的线条:

 1[label sfc-project/src/App.vue]
 2<template>
 3  <div class="wrapper">
 4    <div v-for="airport in airports" :key="airport.abbreviation" class="card">
 5      <p>{{ airport.abbreviation }}</p>
 6      <p>{{ airport.name }}</p>
 7      <p>{{ airport.city }}, {{ airport.state }}</p>
 8    </div>
 9  </div>
10</template>
11
12<script>
13import { ref } from 'vue'
14import data from '@/data/us-airports.js'
15
16export default {
17  name: 'App',
18  setup() {
19    const airports = ref(data)
20
21    return { airports }
22  }
23}
24</script>
25...

在此片段中,您已导入数据并使用模板中的 <div> 元素和 v-for 指令 进行渲染。

在此时,数据已被导入并准备在App.vue组件中使用,但首先添加一些样式,以便用户更容易阅读数据。

 1[label sfc-project/src/App.vue]
 2...
 3<style>
 4#app { ... }
 5
 6.wrapper {
 7  display: grid;
 8  grid-template-columns: 1fr 1fr 1fr;
 9  grid-column-gap: 1rem;
10  max-width: 960px;
11  margin: 0 auto;
12}
13
14.card {
15  border: 3px solid;
16  border-radius: .5rem;
17  padding: 1rem;
18  margin-bottom: 1rem;
19}
20
21.card p:first-child {
22  font-weight: bold;
23  font-size: 2.5rem;
24  margin: 1rem 0;
25}
26
27.card p:last-child {
28  font-style: italic;
29  font-size: .8rem;
30}
31</style>

在这种情况下,您正在使用 CSS 网格将这些机场代码卡组成一个网格的三个。 请注意这个网格是如何设置在 .wrapper 类。 .card 类是包含每个机场代码,名称和位置的卡或部分。 如果您想了解更多关于 CSS 的信息,请查看我们的 如何使用 CSS 来设计 HTML.

打开您的浏览器并导航到localhost:8080。你会发现一些卡片与机场代码和信息:

Three airport cards rendering the data for the US airports dataset

现在您已经设置了初始应用程序,您可以在下一步将数据重塑为单个文件组件。

步骤 2 — 创建单个文件组件

由于 Vue CLI 使用 Webpack来构建您的应用程序成浏览器可以读取的东西,您的应用程序可以使用 SFC 或 .vue 文件,而不是简单的 JavaScript. 这些文件是您创建可扩展和可重复使用的代码的小块的方式。

这些.vue组件通常由以下三种元素组成:<template>,<script><style>元素。SFC组件可以具有 _scoped_ _unscoped_风格。当一个组件有scopeed风格时,这意味着style<>标签之间的CSS只会影响同一个文件中的<template>中的HTML。

随着您的项目的成功设置,您现在将将这些机场卡分解为一个名为AirportCards.vue的组件。 正如现在所说,在App.vue中的HTML不太可重复使用。

在您的终端中,在组件目录中创建此.vue 文件:

1touch src/components/AirportCards.vue

在文本编辑器中打开AiportCards.vue组件. 为了说明如何使用组件重新使用代码块,请将大部分代码从App.vue文件移动到AirportCards.vue组件:

 1[label sfc-project/src/components/AirportCards.vue]
 2<template>
 3  <div class="wrapper">
 4    <div v-for="airport in airports" :key="airport.abbreviation" class="card">
 5      <p>{{ airport.abbreviation }}</p>
 6      <p>{{ airport.name }}</p>
 7      <p>{{ airport.city }}, {{ airport.state }}</p>
 8    </div>
 9  </div>
10</template>
11
12<script>
13import { ref } from 'vue'
14import data from '@/data/us-airports.js'
15
16export default {
17  name: 'Airports',
18  setup() {
19    const airports = ref(data)
20
21    return { airports }
22  }
23}
24</script>
25
26<style scoped>
27.wrapper {
28  display: grid;
29  grid-template-columns: 1fr 1fr 1fr;
30  grid-column-gap: 1rem;
31  max-width: 960px;
32  margin: 0 auto;
33}
34
35.card {
36  border: 3px solid;
37  border-radius: .5rem;
38  padding: 1rem;
39  margin-bottom: 1rem;
40}
41
42.card p:first-child {
43  font-weight: bold;
44  font-size: 2.5rem;
45  margin: 1rem 0;
46}
47
48.card p:last-child {
49  font-style: italic;
50  font-size: .8rem;
51}
52</style>

保存并关闭文件。

接下来,打开您的App.vue文件,现在您可以清理App.vue组件并导入AirportCards.vue:

 1[label sfc-project/src/App.vue]
 2<template>
 3  <AirportCards />
 4</template>
 5
 6<script>
 7import AirportCards from '@/components/Airports.vue'
 8
 9export default {
10  name: 'App',
11  components: {
12    AirportCards
13  }
14}
15</script>
16
17<style scoped>
18#app {
19  font-family: Avenir, Helvetica, Arial, sans-serif;
20  -webkit-font-smoothing: antialiased;
21  -moz-osx-font-smoothing: grayscale;
22  text-align: center;
23  color: #2c3e50;
24  margin-top: 60px;
25}
26</style>

现在AirportCards是一个独立的组件,你已经把它放在<template>的HTML中,就像你想要一个<p>的标签一样。

當您在瀏覽器中開啟「localhost:8080」時,沒有什麼會改變. 相同的三張機場卡仍然會顯示,因為您正在在「」元素中顯示新的SFC。

接下来,再次将该组件添加到模板中,以说明组件的可重复使用性:

1[label /src/App.vue]
2<template>
3  <AirportCards />
4  <airport-cards />
5</template>
6...

您可能会注意到这个新的AirportCards.vue实例正在使用 kebab-casePascalCase 进行引用。在引用组件时,Vue 并不在乎您使用哪个组件。

<$>[注] 注: 您使用的案例取决于个人偏好,但一致性很重要。

打开浏览器并访问localhost:8080。你会发现卡片的重复:

The US airport cards rendered twice in the browser.

这为您的应用程序增加了模块化性,但数据仍然是静态的. 如果您想要显示相同的三个机场,卡的行是有用的,但更改数据源将需要更改硬编码的数据。

步骤 3 – 利用特许权来传输数据

在之前的步骤中,您创建了一个AirportCards.vue组件,该组件从us-airports.js文件中的数据中渲染了一些卡片,此外,您还翻番了相同的组件参考,以说明您如何通过在<模板>中添加该组件的另一个实例来轻松复制代码。

但是,如果数据保持静态,将使未来更改数据变得困难。当您使用 SFC 时,如果您将组件视为函数,则可以有所帮助。这些函数是可以包含参数(props)并返回某些东西(HTML)的组件。

在文本编辑器中打开AirportCards.vue组件. 您正在从us-airports.js文件中导入数据。 删除此导入声明以及在<script>标签中的设置函数:

1[label sfc-project/src/components/AirportCards.vue]
2...
3<script>
4
5export default {
6  name: 'Airports',
7}
8</script>
9...

保存文件. 在此时刻,浏览器中不会显示任何东西。

接下来,通过定义 prop 向前迈进,这个 prop 可以被命名为任何东西;它只是描述进入的数据并将其与一个名称相关联。

要创建一个 prop,请在组件中添加props属性。 此值为一系列的密钥/值对。 密钥是 prop的名称,值是数据的描述。

 1[label sfc-project/src/components/AirportCards.vue]
 2...
 3<script>
 4
 5export default {
 6  name: 'Airports',
 7  props: {
 8    airports: {
 9      type: Array,
10      required: true
11    }
12  }
13}
14</script>
15...

现在,在AirportCard.vue,属性机场是指传输的数据。

接下来,在文本编辑器中打开App.vue组件,如前所述,您将需要从us-airports.js文件中导入数据,并从Vue中导入``ref函数,使其对HTML模板具有反应性:

 1[label sfc-project/src/App.vue]
 2<template>
 3  <AirportCards :airports="usAirports" />
 4  <airport-cards />
 5</template>
 6
 7<script>
 8import { ref } from 'vue'
 9import AirportCards from '@/components/Airports.vue'
10import usAirportData from '@/data/us-airports.js'
11
12export default {
13  name: 'App',
14  components: {
15    AirportCards
16  },
17  setup() {
18    const usAirports = ref(usAirportData)
19
20    return { usAirports }
21  }
22}
23</script>

如果您打开浏览器并访问localhost:8080,您将发现与之前相同的美国机场:

US airports rendered on cards in the browser

您的模板中还有另一个AirportCards.vue实例。由于您在该组件中定义了代理,您可以传输具有相同结构的任何数据,以返回来自不同机场的几张卡片。

App.vue中,导入eu-airports.js文件,将其包装在ref函数中,使其反应性,然后返回:

 1[label /src/App.vue]
 2<template>
 3  <AirportCards :airports="usAirports" />
 4  <airport-cards :airports="euAirports" />
 5</template>
 6
 7<script>
 8...
 9import usAirportData from '@/data/us-airports.js'
10import euAirportData from '@/data/eu-airports.js'
11
12export default {
13  ...
14  setup() {
15    const usAirports = ref(usAirportData)
16    const euAirports = ref(euAirportData)
17
18    return { usAirports, euAirports }
19  }
20}
21</script>
22...

打开您的浏览器并访问localhost:8080。下方您将找到美国机场数据的欧洲机场数据:

US airport data rendered as cards, followed by European airport data rendered in the same way.

您现在已成功地将不同的数据集转移到同一个组件中. 使用props,您基本上正在将数据重新分配到新的名称中,并使用该新名称来引用子组件中的数据。

在这一点上,这个应用程序开始变得更加动态,但你仍然可以做一些其他事情来使这一点更加集中和可重复使用。在Vue.js中,你可以使用名为 slots 的东西。

步骤4 — 使用插槽创建通用卡片组件

插槽是创建可重复使用的组件的好方法,特别是如果你不知道该组件中的HTML是否会是相似的。在上一个步骤中,你创建了另一个AirportCards.vue实例,具有不同的数据。

打开终端并使用触摸命令创建一个新文件. 这个文件将被命名为Card.vue:

1touch src/components/Card.vue

在您的文本编辑器中,打开新的Card.vue组件.您将从AirportCards.vue中取一些CSS并将其添加到这个新组件中。

创建一个<style>标签,并在以下CSS中添加:

1[label sfc-project/src/components/Card.vue]
2<style>
3.card {
4  border: 3px solid;
5  border-radius: .5rem;
6  padding: 1rem;
7  margin-bottom: 1rem;
8}
9</style>

接下来,为该组件创建 HTML 模板。在<style>标签之前,添加一个<template>标签,包含以下内容:

1[label sfc-project/src/components/Card.vue]
2<template>
3  <div class="card">
4
5  </div>
6</template>
7...

<div class="card">之间,添加<slot />组件,这是Vue为您提供的组件,无需导入这个组件,它由Vue.js在全球范围内导入:

1[label sfc-project/src/components/Card.vue]
2<template>
3  <div class="card">
4    <slot />
5  </div>
6</template>

插槽Card.vue组件的标签之间位置的HTML,当它在其他地方引用时。

保存和退出文件。

现在回到AirportCards.vue组件. 首先,导入您刚刚创建的新Card.vue SFC:

 1[label sfc-project/src/components/AirportCards.vue]
 2...
 3<script>
 4import Card from '@/components/Card.vue'
 5
 6export default {
 7  name: 'Airports',
 8  props: { ... },
 9  components: {
10    Card
11  }
12}
13</script>
14...

现在剩下的就是把div代替为card:

 1[label /src/components/AirportCards.vue]
 2<template>
 3  <div class="wrapper">
 4    <card v-for="airport in airports" :key="airport.abbreviation">
 5      <p>{{ airport.abbreviation }}</p>
 6      <p>{{ airport.name }}</p>
 7      <p>{{ airport.city }}, {{ airport.state }}</p>
 8    </card>
 9  </div>
10</template>
11...

由于您在Card.vue组件中有<slot />,所以在<card>标签之间注入了HTML,同时保留了与卡片相关联的所有风格。

当你在localhost:8080上打开浏览器时,你会发现你以前使用过的相同卡片。 现在的区别是你的AirportCards.vue现在引用了Card.vue组件:

US airport data rendered as cards, followed by European airport data rendered in the same way.

要显示插槽的强度,请在应用程序中打开App.vue组件,然后导入Card.vue组件:

 1[label sfc-project/src/App.vue]
 2...
 3<script>
 4...
 5import Card from '@/components/Card.vue'
 6
 7export default {
 8  ...
 9  components: {
10    AirportCards,
11    Card
12  },
13  setup() { ... }
14}
15</script>
16...

<模板>中,在<机场卡>实例中添加下列内容:

 1[label sfc-project/src/App.vue]
 2<template>
 3  <AirportCards :airports="usAirports"/>
 4  <airport-cards :airports="euAirports" />
 5  <card>
 6    <p>US Airports</p>
 7    <p>Total: {{ usAirports.length }}</p>
 8  </card>
 9  <card>
10    <p>EU Airports</p>
11    <p>Total: {{ euAirports.length }}</p>
12  </card>
13</template>
14...

保存文件并访问浏览器中的localhost:8080。您的浏览器现在将显示数据集中的机场数量的额外元素:

US and European airports displayed, along with two cards that display that there are three airports in each dataset

<card />标签之间的HTML并不完全相同,但它仍然呈现出一种通用卡片。

结论

在本教程中,您创建了单个文件的组件,并使用propsslots来创建可重复使用的代码块。在项目中,您创建了一个AirportCards.vue组件,该组件可渲染多个机场卡片。

您最终发现了一些组件是动态的,可以用于许多不同的用途,所有这些都保持代码可维护,并符合软件原则(https://en.wikipedia.org/wiki/Don%27t_repeat_yourself)。

要了解更多关于 Vue 组件的信息,建议您通过 Vue 文档进行准备。 有关 Vue 的更多教程,请参阅 如何使用 Vue.js 系列开发网站页面

Published At
Categories with 技术
comments powered by Disqus