Vue3组件将UI拆分为独立可复用小零件。单文件组件定义后需导入父组件模板使用,也可全局注册。组件独立运行维护自身状态,通过defineProps声明props接收动态数据,用v-bind绑定。子父交互通过事件实现,动态组件用:is切换,被切组件默认卸载,可用keep-alive保持存活。
Vue3组件开发指南
时间:2026-07-27
浏览:354
文章目录
组件基础
组件的作用是将UI拆分为独立、可复用的小模块。这不仅实现了代码层面的解耦,也有助于团队协作和后期维护。
定义组件
如果项目使用构建工具(如Vite),通常将Vue组件定义在单独的.vue文件中,这种形式称为单文件组件,结构清晰且高效。
如果不使用构建流程,也可以使用纯JavaScript对象定义组件,但这种方式不太常用,此处不展开讨论。
使用组件
在父组件中使用子组件时,首先需要将其导入。导入后,在父组件的模板中可以直接像使用HTML标签一样使用该组件。
复制代码<template>
<h1>Here is a child component!h1>
<ButtonCounter />
template>
也可以采用全局注册的方式——将组件注册到全局后,任何组件中都可以直接使用,无需每次导入。
- 每个组件独立运行,维护自己的状态。每次使用组件都会创建一个全新的实例,彼此互不干扰。
传递props
假设正在开发一个博客,希望每篇文章的视觉风格一致,但标题和内容各不相同。此时需要向组件传递数据,而props正是用于此目的。
props是一种特殊的属性(attributes)。要让组件接收数据,必须在组件的props列表中提前声明。defineProps()用于告知框架该组件能够接收哪些数据:
复制代码<template>
<h4>{{ title }}h4>
template>
声明后的props会自动暴露给模板。如果需要进一步操作,defineProps会返回一个对象,包含所有可传入的props:
复制代码const props = defineProps(['title'])
console.log(props.title)
如果未使用,则props需要通过选项式声明,并作为setup()函数的第一个参数传入:
复制代码export default {
props: ['title'],
setup(props) {
console.log(props.title)
}
}
一个组件可以拥有任意数量的props,默认情况下,所有prop接受任意类型的值。
复制代码<BlogPost title="My journey with Vue" />
<BlogPost title="Blogging with Vue" />
<BlogPost title="Why Vue is so fun" />
实际开发中,父组件通常包含一个博客文章数组:
复制代码const posts = ref([
{ id: 1, title: 'My journey with Vue' },
{ id: 2, title: 'Blogging with Vue' },
{ id: 3, title: 'Why Vue is so fun' }
])
然后通过v-for将数据传入子组件:
复制代码<BlogPost
v-for="post in posts"
:key="post.id"
:title="post.title"
/>
子组件接收并渲染:
复制代码<template>
<h4>{{ title }}h4>
template>
- 注意,
:title="post.title"是v-bind:title="post.title"的缩写。v-bind可以将数据动态绑定到HTML属性或组件props上,使HTML属性与JavaScript变量联动。
监听事件
回到组件。有时子组件需要与父组件进行交互——例如,在无障碍场景中,用户点击按钮后文章文字放大,而页面其他部分保持默认字号。
在父组件中,可以添加一个postFontSize的ref来实现此效果:
复制代码const posts = ref([
/* ... */
])const postFontSize = ref(1)
然后在模板中用它控制所有博客文章的字体大小:
复制代码"{ fontSize: postFontSize + 'em' }">
<BlogPost
v-for="post in posts"
:key="post.id"
:title="post.title"
/>
接下来,给组件添加一个按钮:
复制代码
<template>
<div class="blog-post">
<h4>{{ title }}h4>
<button>Enlarge textbutton>
div>
template>
目标效果:子组件的按钮点击后,通知父组件放大所有文章的文字。
实现方案依赖Vue内置的自定义事件系统。父组件可以通过v-on或@选择性监听子组件抛出的事件,这与监听原生DOM事件类似:
复制代码<BlogPost
...
@enlarge-text="postFontSize += 0.1"
/>
- 这里的
@enlarge-text="postFontSize += 0.1"是v-on:enlarge-text="postFontSize += 0.1"的缩写。含义是:一旦enlarge-text事件被触发,就执行postFontSize += 0.1。
子组件则通过调用内置的$emit方法,传入事件名称来抛出事件:
复制代码
<template>
<div class="blog-post">
<h4>{{ title }}h4>
<button @click="$emit('enlarge-text')">Enlarge textbutton>
div>
template>
由于存在@enlarge-text="postFontSize += 0.1"的监听,父组件收到事件后,会更新postFontSize的值。
与props类似,需要抛出的事件也应通过defineEmits()声明:
复制代码
和defineProps类似,defineEmits仅可用于中,且无需额外导入。
通过插槽分配内容
有时希望像原生HTML元素一样向组件中传递内容:
复制代码<AlertBox>
Something bad happened.
AlertBox>
期望渲染效果如下:

这一需求可通过Vue的自定义slot元素轻松实现:
复制代码
<div class="alert-box">
<strong>This is an Error for Demo Purposesstrong>
<slot />
div>
<style scoped>
.alert-box {
/* ... */
}
style>
也就是说,作为一个占位符,父组件传入的内容会被自动渲染到该位置。
app.vue
复制代码<template>
<AlertBox>
Something bad happened.
AlertBox>
template>
AlertBox.vue
复制代码
<div class="alert-box">
<strong>Error!strong>
<br/>
<slot />
div>
动态组件
某些场景需要在两个组件之间来回切换,例如Tab界面。Vue提供了元素和特殊的is属性来解决此问题:
复制代码
<component :is="tabs[currentTab]">component>
传给:is的值可以是以下两种:
- 已注册的组件名
- 导入的组件对象
需要注意的是,当使用在多个组件间切换时,被切掉的组件会被直接卸载。若希望它们保持“存活”状态,可以用组件包裹。
App.vue
复制代码
<div class="demo">
<button
v-for="(_, tab) in tabs"
:key="tab"
:class="['tab-button', { active: currentTab === tab }]"
@click="currentTab = tab"
>
{{ tab }}
button>
<component :is="tabs[currentTab]" class="tab">component>
div>
实用工具推荐
绿化、压缩、噪点和虚拟水印,自由调节做旧程度。
选择画质和输出格式,预览压缩前后的大小。