Vue3组件开发指南

作者:技术拾光

时间:2026-07-27

浏览:354

Vue3组件将UI拆分为独立可复用小零件。单文件组件定义后需导入父组件模板使用,也可全局注册。组件独立运行维护自身状态,通过defineProps声明props接收动态数据,用v-bind绑定。子父交互通过事件实现,动态组件用:is切换,被切组件默认卸载,可用keep-alive保持存活。

文章目录

组件基础

组件的作用是将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>

期望渲染效果如下:

Vue3组件开发指南

这一需求可通过Vue的自定义slot元素轻松实现:

 复制代码<style scoped>
.alert-box {
  /* ... */
}
style>

也就是说,作为一个占位符,父组件传入的内容会被自动渲染到该位置。

app.vue

 复制代码<template>
	<AlertBox>
  	Something bad happened.
	AlertBox>
template>

AlertBox.vue

 复制代码

动态组件

某些场景需要在两个组件之间来回切换,例如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>

实用工具推荐

电子包浆

绿化、压缩、噪点和虚拟水印,自由调节做旧程度。

使用 ›
图片压缩

选择画质和输出格式,预览压缩前后的大小。

使用 ›