news 2026/3/13 5:05:00

Vue.js 组件全面学习指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Vue.js 组件全面学习指南

1 学习指南

1.1 学习目标

  • 认知层级

    目标描述

    对应章节

    了解

    掌握组件化开发思想与核心价值

    2.1 组件化思想

    掌握

    组件注册、父子通信基础用法

    3.1-3.2、4.1-4.2

    熟练

    高级组件特性与复杂场景应用

    4.3-4.5、6.0

    应用

    独立完成中型项目组件拆分与实现

    5.0 实战案例

1.2 前置知识

  • 掌握 Vue 基础语法(模板、指令、响应式数据)
  • 了解 ES6 + 语法(解构、箭头函数、模块化)
  • 具备 HTML/CSS 基础

2 组件的简介

组件是 Vue.js 的核心概念,是可复用的 Vue 实例,相当于页面的 “功能积木”。将复杂页面拆分为独立、可复用的组件,能实现:

  • 代码模块化:单个组件专注单一功能,维护成本降低
  • 复用性提升:同一组件可在多个页面重复使用
  • 协作高效:多人开发时可并行开发不同组件

组件的本质是 “独立的视图 + 逻辑单元”,类比现实中的 “乐高积木”—— 每个积木有固定功能(比如轮子、车身),组合起来形成完整模型(应用)。

3 组件的使用

3.1 组件注册方式

3.1.1 全局注册(全局可用)
// main.js import { createApp } from 'vue' import App from './App.vue' import GlobalComponent from './components/GlobalComponent.vue' const app = createApp(App) // 全局注册:所有组件均可直接使用 app.component('GlobalComponent', GlobalComponent) app.mount('#app')
3.1.2 局部注册(仅当前组件可用)
<LocalComponent /> 局部组件只能在当前父组件使用 --> > // 局部注册:导入即注册,无需额外配置 import LocalComponent from './LocalComponent.vue' </script>

3.2 组件使用规范

注册方式对比

注册方式

适用场景

优点

缺点

最佳实践

全局注册

通用基础组件(如 Button/Icon)

全局可直接使用,无需导入

增加打包体积,未使用组件无法 Tree-Shaking

注册不超过 5 个核心基础组件

局部注册

业务组件(如 TodoInput/TodoItem)

按需导入,减小打包体积

需手动导入后使用

业务模块优先使用,配合自动导入插件

  • 组件名建议使用kebab-case(短横线分隔),如todo-item
  • 单文件组件(SFC)统一后缀为.vue,包含<template>/<script>/` 三部分
  • 样式隔离:在标签添加scoped` 属性,避免样式污染

4 组件之间的通信

组件通信是组件协作的核心,Vue3 提供了多种通信方案,重点关注父子组件通信。

4.1 父组件向子组件通信(已完成)

核心方案:Props 传递(单向数据流:父传子,子不可直接修改 props)

Parent.vue --> > :username="userName" :age="userAge" /> <script setup> import { ref } from 'vue' import ChildComponent from './ChildComponent.vue' const userName = ref('张三') const userAge = ref(18) </script> 组件 ChildComponent.vue --> <template> <p>姓名:{{ username }}</p> <p>年龄:{{ age }}</p> > // 定义props并指定类型、默认值、必填项 const props = defineProps({ username: { type: String, required: true }, age: { type: Number, default: 18 // 未传递时使用默认值 } }) </script>

4.2 子组件向父组件通信

核心方案:自定义事件($emit),类比 “儿子向父亲汇报情况”,子组件触发事件,父组件监听并处理。

4.2.1 基础用法(3 步实现)
  1. 子组件声明可触发的事件(defineEmits)
  1. 子组件触发事件(emit('事件名', 数据))
  1. 父组件监听事件(@事件名="处理函数")
<!-- 子组件 ChildComponent.vue --> ="sendMessage">向父组件发送消息 ="inputValue" placeholder="输入要传递的内容" /> <script setup> import { ref } from 'vue' // 1. 声明可触发的事件(支持多个,数组形式) const emit = defineEmits(['message-sent', 'value-change']) const inputValue = ref('') // 2. 触发事件:第一个参数是事件名,后续是传递的数据 function sendMessage() { emit('message-sent', '子组件问候:你好,父组件!') // 传递字符串 emit('value-change', inputValue.value) // 传递输入框值 } .vue --> @message-sent="handleMessage" @value-change="handleValueChange" /> 的消息:{{ parentMessage }}</p> <p>父组件接收的输入值:{{ parentValue }}</p> > import { ref } from 'vue' import ChildComponent from './ChildComponent.vue' const parentMessage = ref('') const parentValue = ref('') // 3. 监听事件并处理数据 function handleMessage(msg) { parentMessage.value = msg } function handleValueChange(val) { parentValue.value = val } #### 4.2.2 进阶用法:v-model双向绑定(语法糖) `v-model`是`props + emit`的组合,适用于“父子组件数据同步”场景(如自定义输入框): ```vue <!-- 子组件 CustomInput.vue --> :value="modelValue" @input="emit('update:modelValue', $event.target.value)" /> 接收父组件v-model传递的value(默认名modelValue) defineProps(['modelValue']) // 声明更新事件(固定格式:update:modelValue) const emit = defineEmits(['update:modelValue']) .vue --> :Value="searchText" @update:modelValue="searchText = $event" /> --> v-model="searchText" /> 搜索内容:{{ searchText }}</p> > import { ref } from 'vue' import CustomInput from './CustomInput.vue' const searchText = ref('')
4.2.2 注意事项
  • 事件名建议使用kebab-case(短横线分隔),与组件名规范一致
  • 可传递任意类型数据(字符串、对象、数组等)
  • 子组件不可直接修改父组件数据,必须通过 “触发事件” 让父组件自行修改(遵循单向数据流)

5 组件实战案例:TodoList 任务清单

5.1 案例需求

实现一个简易 TodoList,包含功能:

  • 父组件管理任务列表(数据存储)
  • 子组件 1(TodoInput):输入任务并添加到列表(子传父)
  • 子组件 2(TodoItem):展示单个任务,支持删除功能(子传父)
  • 父组件向子组件传递任务数据(父传子)

5.2 代码实现

5.2.1 目录结构
src/ ├── components/ │ ├── TodoInput.vue // 任务输入组件(子) │ └── TodoItem.vue // 单个任务组件(子) └── App.vue // 父组件(任务列表管理)
5.2.2 子组件 1:TodoInput.vue(添加任务)
-input"> v-model="newTodo" placeholder="请输入新任务" @keyup.enter="addTodo" /> click="addTodo">添加</button> </div> { ref } from 'vue' const emit = defineEmits(['add-todo']) // 声明添加事件 const newTodo = ref('') function addTodo() { if (newTodo.value.trim()) { // 传递任务对象给父组件 emit('add-todo', { id: Date.now(), // 用时间戳作为唯一ID content: newTodo.value, done: false }) newTodo.value = '' // 清空输入框 } } <style scoped> .todo-input { margin: 20px 0; display: flex; gap: 10px; } input { flex: 1; padding: 8px; } button { padding: 8px 16px; background: #42b983; color: white; border: none; border-radius: 4px; cursor: pointer; } </style>
5.2.3 子组件 2:TodoItem.vue(单个任务)
<template> class="todo-item"> done: todo.done }" @click="toggleDone"> {{ todo.content }} ="deleteTodo">删除</button> > <script setup> const props = defineProps({ todo: { type: Object, required: true, // 验证todo对象结构 validator: (value) => { return 'id' in value && 'content' in value && 'done' in value } } }) const emit = defineEmits(['delete-todo', 'toggle-done']) // 触发删除事件(传递任务ID) function deleteTodo() { emit('delete-todo', props.todo.id) } // 触发状态切换事件 function toggleDone() { emit('toggle-done', props.todo.id) } </script> oped> .todo-item { display: flex; justify-content: space-between; align-items: center; padding: 8px; border-bottom: 1px solid #eee; } .done { text-decoration: line-through; color: #999; } button { background: #ff4444; color: white; border: none; border-radius: 4px; padding: 4px 8px; cursor: pointer; }
5.2.4 父组件:App.vue(核心管理)
<template> 1>TodoList 任务清单 :输入任务(子传父:添加任务) --> add-todo="handleAddTodo" /> 子组件2:展示任务(父传子:任务数据;子传父:删除/切换) --> todo-list"> <TodoItem v-for="todo in todoList" :key="todo.id" :todo="todo" @delete-todo="handleDeleteTodo" @toggle-done="handleToggleDone" /> </div> > import { ref } from 'vue' import TodoInput from './components/TodoInput.vue' import TodoItem from './components/TodoItem.vue' // 父组件维护任务列表(响应式数据) const todoList = ref([ { id: 1, content: '学习Vue组件通信', done: false }, { id: 2, content: '完成实战案例', done: false } ]) // 处理添加任务(接收子组件传递的任务对象) function handleAddTodo(newTodo) { todoList.value.push(newTodo) } // 处理删除任务(接收子组件传递的任务ID) function handleDeleteTodo(todoId) { todoList.value = todoList.value.filter(todo => todo.id !== todoId) } // 处理切换任务状态(接收子组件传递的任务ID) function handleToggleDone(todoId) { const todo = todoList.value.find(todo => todo.id === todoId) if (todo) todo.done = !todo.done } </script> scoped> h1 { color: #333; } .todo-list { border: 1px solid #eee; border-radius: 4px; padding: 10px; }

5.3 案例效果

- 输入任务内容,点击“添加”或按回车,任务会添加到列表(子传父)

- 点击任务文本,切换完成状态(子传父触发状态更新)

- 点击“删除”按钮,移除对应任务(子传父触发删除)

- 父组件通过props将任务数据传递给`TodoItem`组件(父传子)

5.4 案例核心知识点总结

1. 组件拆分:按功能拆分为“输入组件”“列表项组件”“父组件”,职责单一

2. 父传子:通过props传递任务数据、配置项

3. 子传父:通过自定义事件传递操作(添加/删除/切换)和数据(任务ID/对象)

4. 响应式数据:父组件维护核心数据,子组件仅负责展示和触发事件

如果需要补充某部分细节(如 TypeScript 支持、组件复用技巧),或想扩展其他实战案例(如购物车、表单组件),可以随时告诉我!

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/3/11 18:34:19

用户行为返利业务流程实现

目录 1、引言 2、实现 3、总结 1、引言 在面向用户的平台中&#xff0c;可以在用户各种行为&#xff08;如支付&#xff0c;签到&#xff09;实现后进行用户返利&#xff08;优惠券发放、积分发放等等&#xff09;&#xff0c;可以使用户习惯操作提升系统用户留存与使用。…

作者头像 李华
网站建设 2026/3/10 9:30:04

Python 爬虫实战:Scrapy 框架快速搭建分布式爬虫

前言 在大数据时代&#xff0c;单节点爬虫面对海量数据采集需求时&#xff0c;往往受限于单机的网络带宽、CPU 算力和 IP 资源&#xff0c;采集效率难以满足业务要求。Scrapy 作为一款成熟的 Python 爬虫框架&#xff0c;本身具备轻量级、高扩展性的特点&#xff0c;结合分布式…

作者头像 李华
网站建设 2026/3/11 16:24:40

Python 爬虫实战:爬虫代理 IP 池搭建与自动切换

摘要 本文聚焦爬虫代理 IP 池的核心搭建与自动切换技术&#xff0c;针对反爬机制中 IP 封禁的核心痛点&#xff0c;系统讲解代理 IP 池的架构设计、数据源对接、有效性检测、自动切换及动态维护全流程。实战验证基于IP 检测测试页&#xff08;可直接点击验证 IP 有效性&#x…

作者头像 李华
网站建设 2026/3/13 4:38:24

JAVA面相对象编程—抽象类、接口

#JAVA笔记#抽象类定义抽象类与普通类基本类似&#xff0c;唯一的区别在于使用abstract关键字修饰&#xff0c;且类中有未实现&#xff08;没有方法体&#xff09;的抽象方法&#xff08;abstract修饰&#xff09;。抽象方法必须位于抽象类中&#xff0c;抽象方法只能访问抽象成…

作者头像 李华
网站建设 2026/3/13 8:53:54

2026最新网络安全小白自学之路,别到处拜师了!!

较为完整的学习路线&#xff1a; 这个路线是我和一些已入职大佬来规划整理&#xff0c;也加上了小提示&#xff0c;我也希望你们能看看上面我的心得&#xff0c;都会有所帮助。 第一阶段&#xff0c;初入门学网络基础tip&#xff1a;这部分没有什么逻辑可以说的&#xff0c;半个…

作者头像 李华
网站建设 2026/3/2 10:57:12

加入2025护网,日薪最低1500,能力越强薪资越高!

加入2025护网&#xff0c;日薪最低1500&#xff0c;能力越强薪资越高&#xff01; 什么是护网行动 ** ** 1.护网行动 护网&#xff0c;也称网络保护&#xff0c;是指网络安全人员对企业或组织的网络进行检查、维护和保护&#xff0c;以防止网络受到黑客攻击、病毒、木马或其…

作者头像 李华