关于 components
面向 Vue 开发者的组件基础指南,介绍如何组织界面、组合可复用元素并管理响应式状态,涵盖单文件组件与父子组件协作。
主要功能
- 01Vue 组件结构
- 02单文件组件组织方式
- 03父子组件的 props 与事件
- 04使用 ref() 和 reactive() 管理状态
- 05提取可复用界面组件
适用场景
- 01规划 Vue 应用界面结构
- 02将复杂视图拆分为子组件
- 03复用重复出现的界面元素
- 04构建响应式交互组件
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ patternsdev/ skills --skill components安装后在 Claude Code 中输入/components确认已加载。
详细介绍
组件
目录
Vue 组件是 Vue 应用的构建块,能够将标记(HTML)、逻辑(JS)和样式(CSS)组合在一起。
在 Vue 应用中工作时,重要的是要了解,UI 中显示的几乎所有元素通常都是 Vue 组件的一部分。这是因为 Vue 应用通常由相互嵌套的组件构成,从而形成层级结构。
适用场景
- 将此内容作为构建任何 Vue 应用的基础知识
- 这有助于了解如何在 Vue 中构建、组合和复用 UI 元素
使用说明
- 使用单文件组件(
.vue文件),并包含<template>、<script setup>和<style>部分 - 将大型组件中可复用的部分提取为较小的子组件
- 使用
ref()处理响应式基本类型值,使用reactive()处理响应式对象 - 使用 props 将数据从父组件传递给子组件;通过触发事件将数据从子组件传递给父组件
详情
可复用性和可维护性是构建结构良好的组件尤为重要的主要原因。
为了更好地理解组件,我们来创建一个组件。在不包含构建流程(例如 Webpack)的应用中,创建 Vue 组件最简单的方法是创建一个包含 Vue 特定选项的纯 JavaScript 对象。
export default {
props: ["name"],
template: `<h1>Hello, my name is {{ name }}</h1>`,
};
该组件定义了一个 props 属性,其中接收一个名为 name 的 prop。Props 用于将数据从父组件传递到组件。
template 属性定义了组件的 HTML 模板。在本例中,它包含一个 <h1> 标题标签,显示文本 "Hello, my name is",后面跟着 name prop 的值。该值使用 Vue 的双大括号语法 {{ }} 渲染。
除了将组件定义为纯 JavaScript 对象外,在 Vue 中创建组件最常见的方式是使用单文件组件(SFC)。单文件组件允许我们在一个特殊的 .vue 文件中定义组件的 HTML、CSS 和 JS,如下所示:
<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 组件中的响应式状态提供了一种无缝管理和跟踪数据变化的方式,让构建交互式动态用户界面变得更加简单。
总结
本文旨在简单介绍组件这一概念。在其他文章和指南中,我们将深入探讨使用 Vue 和 Vue 组件时常见且重要的模式,包括但不限于:
- 使用
<script setup>语法 - 创建可组合函数以复用有状态逻辑
- 通过 provide/inject 在多个组件间传递数据
- 了解应用级状态管理
- 使用动态组件在组件之间动态切换
- 使用 JSX 渲染组件模板
- 以及更多内容。