Vue父子组件通信实战:Props与$emit详解

【Vue】props + $emit 实现父子组件传值【实战篇】 props + $emit 实现父子组件传值 例子要求: 通过例子要求我们可以分析出: 三个组件 主组件(父组件–展示个人信息列表~) 新增子组件(子组件–填写数据、新增用户) 详情子组件(子组件–查看点击的当前用户的个人信息详情) 既然有父子组件,那么他们其中必然需要联系,这时候 props、$emit 就派上用场了!!! 在这之前:如果你还不了解props、$emit、$parent,你可以先看看下面的博客,理解后再看本篇文章: 了解何为 props ?该如何使用呢 ? 何为 $emit ? 如何 阅读详情

1. Vue 父子组件通信的核心价值

在 Vue 开发中,组件化架构就像搭积木一样,父子组件之间的数据流动就是连接这些积木的卡扣。我刚开始用 Vue 时,最头疼的就是明明数据在父组件里,子组件却拿不到;或者子组件修改了数据,父组件却毫不知情。经过多个项目的实战,我总结出这套父子通信的完整方案,帮你避开我踩过的那些坑。

父子通信本质上要解决三个问题:父传子(Props)、子传父($emit)、兄弟组件间通信(通过父组件中转)。下面我会用实际业务场景中的例子,带你掌握每种方式的适用场景和具体写法,包括那些官方文档里没明说的细节技巧。

2. 父组件向子组件传值

2.1 Props 基础用法

假设我们有个电商项目,父组件是商品列表,子组件是单个商品卡片。父组件需要把商品数据传递给子组件:

<!-- 父组件 -->
<template>
  <ProductCard 
    v-for="product in products" 
    :key="product.id"
    :title="product.name"
    :price="product.price"
    :inventory="product.stock"
  />
</template>

<script>
import ProductCard from './ProductCard.vue'

export default {
  components: { ProductCard },
  data() {
    return {
      products: [
        { id: 1, name: 'Vue 实战教程', price: 99, stock: 10 },
        // 更多商品...
      ]
    }
  }
}
</script>

子组件接收这些 props 时,有几种声明方式:

<!-- 子组件 ProductCard.vue -->
<script>
export default {
  // 简单声明(不推荐)
  props: ['title', 'price', 'inventory'],
  
  // 带类型检查(推荐)
  props: {
    title: String,
    price: Number,
    inventory: Number
  },
  
  // 完整写法(生产环境必备)
  props: {
    title: {
      type: String,
      required: true,
      validator: value => value.length <= 50
    },
    price: {
      type: Number,
      default: 0,
      validator: value => value >= 0
    }
  }
}
</script>

关键经验:props 的完整写法虽然啰嗦,但能避免 80% 的数据类型错误。特别是 required 和 validator 能帮你在开发阶段就发现问题。

2.2 Props 的单项数据流陷阱

新手常犯的错误是直接在子组件修改 props:

<!-- 错误示范 -->
<template>
  <button @click="price -= 10">降价</button>
</template>

<script>
export default {
  props: ['price'],
  methods: {
    // 直接修改 props 会导致警告
    discount() {
      this.price -= 10 
    }
  }
}
</script>

正确的做法有两种:

  1. 把 props 转为本地 data:
<script>
export default {
  props: ['initialPrice'],
  data() {
    return {
      localPrice: this.initialPrice
    }
  }
}
</script>
  1. 通过 $emit 通知父组件修改(见第3章)

避坑指南:当 props 是对象/数组时,虽然 Vue 不会阻止你直接修改属性(如 this.product.name = 'new'),但这会导致数据流难以追踪。最佳实践是始终遵循单向数据流原则。

3. 子组件向父组件传值

3.1 $emit 基础用法

继续电商的例子,当用户点击"加入购物车"按钮时,子组件需要通知父组件:

<!-- 子组件 ProductCard.vue -->
<template>
  <button @click="addToCart">加入购物车</button>
</template>

<script>
export default {
  props: ['id'],
  methods: {
    addToCart() {
      this.$emit('add-to-cart', {
        productId: this.id,
        quantity: 1,
        timestamp: Date.now()
      })
    }
  }
}
</script>

父组件监听这个自定义事件:

<!-- 父组件 -->
<template>
  <ProductCard 
    @add-to-cart="handleAddToCart"
  />
</template>

<script>
export default {
  methods: {
    handleAddToCart(payload) {
      console.log('添加商品:', payload.productId)
      // 调用购物车 API...
    }
  }
}
</script>

3.2 事件命名最佳实践

我推荐使用 kebab-case 事件名(如 add-to-cart),因为:

  1. Vue 官方风格指南明确建议
  2. 和 HTML 属性命名风格一致
  3. 避免和原生事件冲突(如 click)

调试技巧:在组件内用 this._events 可以查看当前组件上的所有监听器,但注意这是内部 API,不要在生产环境使用。

3.3 v-model 的双向通信魔法

v-model 本质上是 props + $emit 的语法糖。比如实现一个自定义计数器:

<!-- 子组件 MyCounter.vue -->
<template>
  <button @click="change(value - 1)">-</button>
  <span>{{ value }}</span>
  <button @click="change(value + 1)">+</button>
</template>

<script>
export default {
  props: ['value'],
  methods: {
    change(newVal) {
      this.$emit('input', newVal)
    }
  }
}
</script>

父组件使用:

<MyCounter v-model="count" />

等价于:

<MyCounter :value="count" @input="count = $event" />

高级技巧:Vue 2.3+ 可以通过 model 选项修改默认的 prop 和 event 名称:

export default {
  model: {
    prop: 'currentValue',
    event: 'change'
  }
}

4. 复杂场景下的通信方案

4.1 兄弟组件通信

当两个子组件需要通信时,正确的做法是通过共同的父组件中转:

父组件
├── 子组件A(触发事件)
└── 子组件B(接收 props)

具体实现:

<!-- 父组件 -->
<template>
  <ChildA @search="handleSearch" />
  <ChildB :keywords="keywords" />
</template>

<script>
export default {
  data() {
    return {
      keywords: ''
    }
  },
  methods: {
    handleSearch(val) {
      this.keywords = val
    }
  }
}
</script>

4.2 深层嵌套组件通信

对于多层嵌套的组件(如 A > B > C > D),用 props 逐层传递会非常繁琐。这时可以用:

  1. provide/inject (适合全局配置)
// 祖先组件
export default {
  provide() {
    return {
      theme: 'dark' // 非响应式!
    }
  }
}

// 后代组件
export default {
  inject: ['theme']
}

重要限制:provide 默认不是响应式的。如果需要响应式,可以传递一个对象或使用 Vue.observable:

provide() {
  return {
    theme: Vue.observable({ mode: 'dark' })
  }
}
  1. Event Bus (小型项目适用)
// event-bus.js
import Vue from 'vue'
export default new Vue()

// 组件A(发送)
import bus from './event-bus'
bus.$emit('message', 'hello')

// 组件B(接收)
bus.$on('message', text => {
  console.log(text)
})

使用建议:Event Bus 适合简单场景,但在大型项目中容易导致事件混乱。Vue 3 已移除 $on/$off,推荐用 mitt 等第三方库。

4.3 状态管理方案对比

当项目复杂度上升时,应该考虑 Vuex:

方案 适用场景 优点 缺点
Props/Events 简单父子通信 简单直接 深层嵌套时繁琐
Event Bus 跨组件简单通信 轻量 难以维护,Vue 3 不支持
provide/inject 全局配置 避免 prop 透传 非响应式(需额外处理)
Vuex 中大型项目 集中管理,调试工具 增加复杂度

5. 实战中的常见问题

5.1 异步数据加载问题

当父组件异步获取数据后传递给子组件时,子组件可能已经渲染完成:

<!-- 父组件 -->
<template>
  <Child :data="asyncData" />
</template>

<script>
export default {
  async created() {
    this.asyncData = await fetchData() // 异步请求
  }
}
</script>

解决方案:

  1. 在子组件中添加 loading 状态:
<!-- 子组件 -->
<template>
  <div v-if="!data">加载中...</div>
  <div v-else>显示数据</div>
</template>
  1. 使用 v-if 控制子组件渲染:
<Child v-if="asyncData" :data="asyncData" />

5.2 大型对象性能优化

当传递大型对象时,直接绑定整个对象可能导致不必要的渲染:

<!-- 不推荐 -->
<Child :product="bigProductObject" />

<!-- 推荐 -->
<Child 
  :name="product.name"
  :price="product.price"
  :inventory="product.inventory"
/>

或者使用计算属性提取所需字段:

computed: {
  basicProductInfo() {
    return {
      name: this.product.name,
      price: this.product.price
    }
  }
}

5.3 事件监听的内存泄漏

在动态组件中,如果忘记移除事件监听会导致内存泄漏:

// 错误示范
created() {
  this.$on('custom-event', this.handler)
}

// 正确做法
beforeDestroy() {
  this.$off('custom-event', this.handler)
}

对于 Event Bus 的使用尤其要注意这点。

6. Vue 3 中的变化

6.1 v-model 升级

Vue 3 中 v-model 可以绑定多个值:

<CustomInput 
  v-model:title="pageTitle"
  v-model:content="pageContent"
/>

<!-- 子组件 -->
<script setup>
defineProps(['title', 'content'])
defineEmits(['update:title', 'update:content'])
</script>

6.2 事件发射器变化

Vue 3 的 Composition API 中:

import { defineEmits } from 'vue'

const emit = defineEmits(['change', 'delete'])

function handleClick() {
  emit('change', newValue)
}

6.3 provide/inject 响应式

Vue 3 的 provide 默认支持响应式:

import { provide, ref } from 'vue'

setup() {
  const count = ref(0)
  provide('count', count) // 响应式
}

7. 我的实战心得

  1. 命名一致性 :团队内统一 props 和事件命名规范(如都用 kebab-case),能显著降低沟通成本。

  2. 文档注释 :为每个 prop 添加 JSDoc 注释,方便后续维护:

    props: {
      /**
       * 商品主标题
       * @type {String}
       * @required
       */
      title: { type: String, required: true }
    }
    
  3. 类型检查 :即使不用 TypeScript,也要充分利用 Vue 的运行时类型检查,能捕获大部分低级错误。

  4. 调试技巧 :在 Chrome 开发者工具中,可以使用 $vm0.$props 快速查看组件实例的 props 值。

  5. 性能监控 :当发现组件频繁更新时,检查是否传递了不必要的大对象或频繁变化的引用类型。

最后提醒:父子通信就像两个人对话,重要的是建立清晰的协议(props 和 events)。在项目初期多花时间设计好组件接口,后期维护能省下 50% 以上的时间。

Vue 父子组件通信进阶版:深入理解 Props、$emit 和 provide/inject 通过深入理解 Vue 组件通信的高级用法,我们可以更好地应对各种场景和需求。合理使用 Props、$emit 和 provide/inject 可以让你的组件架构更加清晰和灵活。。 阅读详情

相关推荐

Vue3 中 props 与 $emit 的使用及 defineProps 与 defineEmits 的区别详解

Vue父子组件通信摘要 Vue父子组件通信遵循单向数据流原则,父组件通过props传递数据给子组件,子组件通过$emit触发事件反馈给父组件。Vue3提供了两种写法:传统Options API(使用props和$emit)和Composition API的<script setup>语法糖(使用defineProps和defineEmits宏函数)。新版写法更简洁,且支持TypeScript类型安全。需要注意:不能解构props,宏函数必须在顶层调用。

2401_87008233的博客 1030

vue 父子组件间通信实例讲解(props、r e f 、 ref、ref、emit)

vue之父子组件间通信实例讲解(props、$ref、$emit)_leilei__66的博客-优快云博客vue之父子组件间通信实例讲解(props、ref、ref、ref、emit)组件是 vue.js 最强大的功能之一,而组件实例的作用域是相互独立的,这就意味着不同组件之间的数据无法相互引用。那么组件间如何通信,也就成为了vue中重点知识了。这篇文章将会通过props、$ref和 $emit 这几个知识点,来讲解如何实现父子组件间通信。在说如何实现通信之前,我们先来建两个组件father.vue和ch

yonghutwo的专栏 302

Vue 组件通信的 5 种常用方式:从 props 到 $emit 全解析

props和$emit:适用于父子组件之间的通信。$attrs和$listeners:适用于非父子组件之间的通信。:适用于跨层级组件之间的通信。Vuex:适用于全局状态管理,适用于复杂的应用。根据实际需求选择合适的通信方式,可以提高代码的可维护性和开发效率。

bairuoqing的专栏 855

vue父子组件传值之 $emit和props

vue父子组件传值之 $emit和props前言子组件向父组件传值父组件向子组件传值 前言 在进行vue的项目中,我们难免会需要父子组件之间进行传值,父子组件传值可以通过 $emit和props , eventbus, vuex等,本文主要介绍第一种方法。 子组件向父组件传值 子组件向父组件传值利用的是 $emit 假设我们的父组件为: <app></app> 里面嵌套了子组件: <app> <child></child> </app&g

小鱼干儿的博客 1万+

RPA实战-UiPath自动化处理Outlook邮件附件全流程解析

本文详细解析了如何使用UiPath实现Outlook邮件附件的自动化处理全流程,涵盖环境配置、核心流程实现、高级功能扩展及性能优化技巧。通过RPA技术,企业可大幅提升邮件附件处理效率,减少人工操作错误,适用于财务、物流等多个场景。

weixin_33701251的博客 428

COD论文笔记VSCode: General Visual Salient and Camouflaged Object Detection with 2D Prompt Learning

VSCode模型通过引入领域特定提示和任务特定提示,结合提示区分损失,成功地在单一模型中处理多个显著目标检测和伪装目标检测任务。这种方法不仅提高了模型的性能,还展示了其对未见任务的泛化能力。作者使用 Visual saliency transformer ICCV 2021 作为baseline model这张图展示了VSCode模型的整体框架,特别强调了2D提示学习方法。

985小菜鸡 1628

vue之父子组件间通信实例讲解(props、$ref、$emit)

组件是 vue.js 最强大的功能之一,而组件实例的作用域是相互独立的,这就意味着不同组件之间的数据无法相互引用。那么组件间如何通信,也就成为了vue中重点知识了。这篇文章将会通过props、$ref和 $emit 这几个知识点,来讲解如何实现父子组件间通信。 在说如何实现通信之前,我们先来建两个组件father.vue和child.vue作为示例的基础: 这两部分的代码都很清晰明了,父组件通过...

weixin_43989275的博客 5967

基于 国产USRP B210 的通信+侦测+干扰三合一实验平台,解锁无线攻防全场景!

在当代复杂电磁环境与多样化通信需求并存的背景下,软件定义无线电(SDR)技术正展现出前所未有的系统灵活性与功能可重构性。由两台USRP-LW B210软件无线电设备模拟无线链路通信过程,能够模拟多种无线通信信号传输及图像传输场景,适用于通信协议验证、抗干扰测试及教学实验。,支持"通信-侦测-干扰-优化"的闭环实验流程,为无线通信领域的教学科研与工程应用提供了一套经济高效、功能完备的解决方案。系统可对通信链路信号进行快速、自动化侦测、识别、告警,并支持多种干扰信号生成、模式切换及效果评估功能。

luowave2012的博客 832

Vue 13 | 父子组件通信props/$emit

v-slot:可以实现父子组件单向通信(父向子传值),在实现可复用组件,向组件中传入DOM节点、html等内容以及某些组件库的表格值二次处理等情况时,可以优先考虑v-slot。props/$emit 可以实现父子组件的双向通信,父组件通过props的方式向子组件传递数据,而通过$emit 子组件可以向父组件通信。父子组件间的通信,父子组件中都定义了一个输入框与显示内容,需要子组件输入的内容能够在父组件中显示,父组件中输入的内容能够在子组件中显示。下一步完成在子组件中输入,在父组件中显示。

千禧年无敌优香大王的博客 815

18、知识表示与学习范式

本文探讨了智能系统中的核心组成部分——知识表示与学习范式。从基础知识到实际应用,详细解析了符号表示、框架表示、语义网络和本体表示等知识表示方法,并介绍了监督学习、无监督学习、半监督学习和强化学习等学习范式。此外,还深入分析了这些技术在自然语言处理、图像识别和推荐系统等领域的具体应用及操作步骤。最后,展望了未来可能的技术发展方向。

ttt77的博客 84

SAP FI 会计科目表(COA)可直接套用配置模板

摘要:本文提供了SAP S/4HANA环境下可直接套用的会计科目表(COA)配置模板,包含科目编码规则、号段规划、科目组设置等核心内容。模板采用10位数字编码,按资产(1000)、负债(2000)、权益(3000)、成本(4000)、收入(5000)、费用(6000)六大类划分号段,并预设科目组控制字段状态。适用于集团/单一公司、国内/跨国企业场景,支持多表架构映射,配置完成后可通过事务码SAKO验证科目清单。模板遵循"前4位固定一级科目"原则,企业可根据行业特性调整明细科目。

金牌架构师 267

Vue父子组件间通信:Props与$emit的用法

父组件:直接引入并包裹子组件的组件。子组件:被父组件通过标签形式调用的组件。父 → 子 -----------Props -----------初始化数据传递。子 → 父 --------$emit + @ --------子组件操作反馈。

Lthan7的博客 1299

大模型——Coze工作流实战:一键生成像素风格视频

本文介绍了如何利用Coze平台工作流生成像素风格心理学短视频的方法。通过创建工作流、设置变量节点、调用大模型生成文案、数据格式化处理、合成音频、生成字幕等步骤,最终实现从输入主题到生成完整视频的自动化流程。文章详细展示了每个节点的具体配置方法,包括提示词编写和数据处理脚本,为读者提供了完整的像素风格视频制作解决方案。

820

【前端面试题之Vue篇】(1)父子组件通信方式Props/$emit

Vue中父子组件利用Props和$emit进行通信传值,其中介绍了Props和$emit的定义和如何在父子组件中的使用,怎么实现通信传值的。

CHLing19971130的博客 2402

C#跨平台制图新纪元:Mapsui,一库在手,地图我有

深入学习Mapsui的渲染机制,定制属于你的地图样式,无论是颜色、图标还是文字,都可以随心所欲。

java专栏 1457

《open3D+pyqt》点云读取、显示与保存

《open3D+pyqt》第一章:点云读取与显示一、效果展示二、环境配置三、代码3.1 qt designer设置3.2 生成ui,qrc的py文件3.3 py文件代码 一、效果展示 二、环境配置 环境配置:Anconda+pycharm+pyqt+open3d+pyqtgraph 显示界面:这里选择pyqtgraph 参考网上教程 三、代码 3.1 qt designer设置 界面布局参照《PCL+QT》教程,界面设置:布局如下: 布局参数参考: 3.2 生成ui,qrc的py文件 3.3 py

阁楼 7113

组件间通信:props与$emit

一、props / $emit 父组件通过props的方式向子组件传递数据,而通过$emit 子组件可以向父组件通信。 1. 父组件向子组件传值 下面通过一个例子说明父组件如何向子组件传递数据:在子组件article.vue中如何获取父组件section.vue中的数据articles:['红楼梦', '西游记','三国演义'] <!--父组件 Father.vue--> <template> <Child :articleList="articleList">&

AndrewNeo 2544

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

vue父子组件通信props、$refs、$emit及非父子组件vuex的使用

vue父子组件通信方法props、$refs、$emit及非父子组件通信vuex使用方法总结。

m0_46169419的博客 4270

迈瑞BS系列全自动生化分析仪LIS协议接口手册(内含HL7和ASTM)

迈瑞BS系列全自动生化分析仪LIS协议接口手册,内含HL7和ASTM)

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

VUE 父子组件的传递 props、$refs 、 $emit、$parent、$children、$root

转载:https://blog.youkuaiyun.com/alokka/article/details/87104189 组件是 vue.js 最强大的功能之一,而组件实例的作用域是相互独立的,这就意味着不同组件之间的数据无法相互引用。那么组件间如何通信,也就成为了vue中重点知识了。这篇文章将会通过props、$ref和 $emit 这几个知识点,来讲解如何实现父子组件间通信。 1.父向子 通过 p...

xqhys的博客 3004

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

vue--父子组件间通信实例讲解(props、$ref、$emit)

vue--父子组件间通信实例讲解props、$ref、$emit分别举例 先说结论 prop和$ref都是父组件向子组件通信 prop: 着重于数据的传递,它并不能调用子组件里的属性和方法。 像创建文章组件时,自定义标题和内容这样的使用场景,最适合使用prop。 $ref: 着重于索引,主要用来调用子组件里的属性和方法,其实并不擅长数据传递。 而且ref用在dom元素的时候,能使到选择器的作用,这...

echo_s 快乐de小媛~ 1699

vue父子组件通信props、$emit

vue父子组件通信props、$emit 通过props从父组件传递到子组件 <script> // 1、创建父&子组件 Vue.component('Parent',{ // 3、子组件挂载到父组件上 通过自定义属性传递数据 template:` <d...

煮酒客的博客 356

Vue组件通信方式 props/$emit

自定义事件本质是由子组件向父组件传递信息 <template> <div role="alert" :class="['el-alert',changeAlert,'is-center','is-light']"> <i :class="['el-alert__icon',changeIcon]"></i> <div class="el-alert__content"> <slo

NolanKy 的 技术博客 975

vue之父子组件间通信传值(props、$ref、$emit)

组件间如何通信,也就成为了vue中重点知识了。这篇文章将会通过props、$ref和 $emit 这几个知识点,来讲解如何实现父子组件间通信。 组件是 vue.js 最强大的功能之一,而组件实例的作用域是相互独立的,这就意味着不同组件之间的数据无法相互引用。那么组件间如何通信,也就成为了vue中重点知识了。这篇文章将会通过props、$ref和 $emit 这几个知识点,来讲解如何实现父子组件间...

weixin_42420652的博客 1420

在vue2和vue3中如何实现父子组件通信?请对比 props/$emit、provide/inject 和 Vuex/Pinia 的适用场景

前端小伙伴们,有没有被组件通信搞到抓头发?父组件传值给子组件要写10层`props`,子组件回传得套娃式`$emit`,跨层组件传值像玩俄罗斯方块……今天咱们就盘一盘Vue的组件通信全家桶——`props/$emit`、`provide/inject`和`Pinia`,从基础到进阶,手把手教你选对工具,告别“传值地狱”!

前端大白话 1128

vue父子组件通信(props、$refs 、 $emit、$parent、$children、$root)

vue父子组件通信(props、$refs 、 $emit、$parent、$children、$root)Vue组件间的通信非常重要下面一起学习吧!props,$emit功能快捷键合理的创建标题,有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants创建一个自定义列表如何创建一个注脚注释也是必不可少的KaTeX数学公式新的甘特图功能,丰富你的文章UML 图表FLowchart流程图导出与导入导出导入 Vue组件

weixin_44705688的博客 947
上一篇: Java多线程并发编程核心实战:从线程状态到线程池与并发工具
下一篇: 线程与多线程:从核心原理到线程池配置的工程实战指南
随缘惜情
博客等级 码龄8年 35粉丝 1万+原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值