设计模式
组件
Vue 组件是 Vue 应用的构建块,它允许我们将标记(HTML)、逻辑(JS)和样式(CSS)耦合在其中。
在 Vue 应用中工作时,重要的是要理解,UI 中显示的几乎所有元素通常都是 Vue 组件的一部分。这是因为 Vue 应用通常由嵌套在组件中的组件组成,形成一个层次结构。
可重用性和可维护性是构建具有良好结构组件的应用程序尤为重要的主要原因之一。
为了更好地理解组件,我们将创建一个组件。在不包含构建过程(例如 Webpack)的应用程序中创建 Vue 组件的最简单方法是创建一个包含 Vue 特定选项的普通 JavaScript 对象。
export default {
props: ["name"],
template: `<h1>Hello, my name is {{ name }}</h1>`,
};
组件定义了一个 props
属性,它接受名为 name
的单个道具。道具是一种将数据从父组件传递到子组件的方法。
template
属性定义了组件的 HTML 模板。在本例中,它包含一个显示文本 "Hello, my name is"
的 <h1>
标题标签,后跟 name
道具的值,该值使用 Vue 的双花括号语法 {{ }}
渲染。
除了将组件定义为普通 JavaScript 对象之外,在 Vue 中创建组件的最常见方法是使用单文件组件 (SFC)。单文件组件是允许我们将组件的 HTML、CSS 和 JS 都定义在一个特殊的 .vue
文件中的组件,如下所示
<template>
<h1>Hello, my name is {{ name }}</h1>
</template>
<script setup>
const { name } = defineProps(["name"]);
</script>
注意:Vue 中的单文件组件是由于像 Vite 这样的构建工具才得以实现。这些工具帮助将
.vue
组件编译成浏览器可以理解的普通 JavaScript 模块。
组件 = 构建块
我们将完成一个简单的练习来说明如何将组件拆分为更小的组件。考虑以下虚构的 Tweet
组件
上面的组件可以使用以下方法实现
<template>
<div class="Tweet">
<image class="Tweet-image" :src="image.imageUrl" :alt="image.description" />
<div class="User">
<image class="Avatar" :src="author.avatarUrl" :alt="author.name" />
<div class="User-name">{{ author.name }}</div>
</div>
<div class="Details">
<div class="Tweet-text">{{ text }}</div>
<div class="Tweet-date">{{ formatDate(date) }}</div>
<!-- ... -->
</div>
</div>
</template>
<script setup>
// ...
</script>
可以查看上面的组件,并认为它难以操作,因为它过于集中,并且重用它各个部分也可能很困难。为了使事情更具可组合性,我们可以从这个组件中提取一些组件。
我们可以让主 Tweet
组件成为 TweetUser
和 TweetDetails
组件的父组件。TweetUser
将显示用户的信息,并成为显示用户头像的 TweetAvatar
组件的父组件。TweetDetails
只需在推文中显示其他信息,例如推文文本和提交日期。组件树将如下所示
首先,我们可以创建子 TweetAvatar
组件来包含头像图像元素。
<template>
<image class="Avatar" :src="author.avatarUrl" :alt="author.name" />
</template>
<script setup>
// ...
</script>
然后,我们可以创建 TweetUser
组件,它渲染 TweetAvatar
组件和相关用户信息。
<template>
<div class="User">
<TweetAvatar />
<div class="User-name">{{ author.name }}</div>
</div>
</template>
<script setup>
import { TweetAvatar } from "./TweetAvatar.vue";
</script>
我们可以创建 TweetDetails
组件来渲染推文中剩余的信息。
<template>
<div class="Details">
<div class="Tweet-text">{{ text }}</div>
<div class="Tweet-date">{{ formatDate(date) }}</div>
<!-- ... -->
</div>
</template>
<script setup>
// ...
</script>
最后,我们可以使用这些新创建的子组件来简化父 Tweet
组件的模板。
<template>
<div class="Tweet">
<image class="Tweet-image" :src="image.imageUrl" :alt="image.description" />
<TweetUser :author="author" />
<TweetDetails :text="text" :date="date" />
</div>
</template>
<script setup>
// ...
</script>
提取组件似乎是一项繁琐的工作,但拥有可重用组件在为大型应用程序编码时会更容易。在简化组件时需要考虑的一个好的标准是——如果您的 UI 的一部分被多次使用(Button
、Panel
、Avatar
),或者它本身足够复杂(App
、FeedStory
、Comment
),它就是一个很好的候选者,可以提取到单独的组件中。
响应式状态
响应式状态是 Vue 组件中的一个基本概念,它使动态和响应的用户界面成为可能。它允许组件自动更新和反映其数据中的更改。
在 Vue 中,我们可以使用 ref()
函数(对于独立的原始值)和 reactive()
函数(对于对象)来定义响应式数据属性。让我们考虑一个简单的计数器组件示例
<template>
<div>
<h2>Counter: {{ count }}</h2>
<button @click="increment">Increment</button>
<button @click="decrement">Decrement</button>
</div>
</template>
<script setup>
import { ref } from "vue";
const count = ref(0);
const increment = () => {
count.value++;
};
const decrement = () => {
count.value--;
};
</script>
在上面的示例中,我们定义了一个响应式属性 count
并将其初始化为 0。然后,模板使用双花括号 {{ }}
来显示 count
的当前值。
模板还包含两个按钮:"Increment"
和 "Decrement"
,它们使用 @click
指令绑定到相应的 increment()
和 decrement()
方法。在这些方法中,我们访问并修改响应式 count
属性的值。Vue 检测到更改并自动更新组件的渲染以反映新值。
Vue 组件中的响应式状态提供了一种无缝的方式来管理和跟踪数据更改,使其更易于构建交互式和动态的用户界面。
1<template>2 <div class="demo tab">3 <h2>Counter: {{ count }}</h2>4 <button @click="increment">Increment</button>5 <button @click="decrement">Decrement</button>6 </div>7</template>89<script setup>10import { ref } from "vue";1112const count = ref(0);1314const increment = () => {15 count.value++;16};1718const decrement = () => {19 count.value--;20};21</script>
结论
本文旨在简单介绍组件的概念。在其他文章和指南中,我们将深入了解使用 Vue 和 Vue 组件时常见的和重要的模式。这包括但不限于
- 使用
<script setup>
语法 - 创建可组合组件以重用有状态逻辑
- 使用提供/注入将数据向下传递到多个组件
- 了解应用程序范围内的状态管理
- 使用动态组件在组件之间动态切换
- 使用 JSX 渲染组件模板
- 等等。