作为一名刚接触 Vue 不久的大二前端学习者,最近在做课程小作业时被组件通信搞得头都大了。明明看着教程敲代码,却总是出现 “父组件拿不到子组件数据” 或者 “子组件接收不到父组件参数” 的问题。经过几天的踩坑总结,终于理清了最基础的父子组件通信逻辑,今天就来和大家分享一下我的学习心得。

一、为什么需要组件通信?

刚开始学 Vue 时我一直不懂,为什么不能直接在子组件里调用父组件的数据?后来才明白,Vue 的组件就像一个个独立的 “小模块”,每个组件都有自己的作用域。就像现实中,孩子不能随便翻父母的抽屉,父母也不能直接闯进孩子的房间 —— 组件之间需要有规范的 “沟通方式”,这样代码才不会乱成一锅粥。

最常见的组件关系就是父子关系:比如一个页面(父组件)里包含了一个按钮组件(子组件),页面需要告诉按钮 “你应该显示什么文字”,按钮被点击后需要告诉页面 “我被点击了”。这就是最典型的父子组件通信场景。

二、父传子:用 props 传递数据

父组件给子组件传数据,就像父母给孩子递东西,需要孩子先 “伸出手”—— 也就是在子组件中定义 props 来接收。

1. 父组件如何发数据?

假设父组件是Parent.vue,我们想给子组件传一个 “用户名称”:

vue

<template>
  <div class="parent">
    <h3>我是父组件</h3>
    <!-- 用属性的方式给子组件传值 -->
    <Child :username="parentName" />
  </div>
</template>

<script>
import Child from './Child.vue' // 引入子组件
export default {
  components: { Child },
  data() {
    return {
      parentName: '小明' // 要传递给子组件的数据
    }
  }
}
</script>

2. 子组件如何接数据?

子组件Child.vue需要通过 props 声明接收:

vue

<template>
  <div class="child">
    <h4>我是子组件</h4>
    <p>父组件传来的名字:{{ username }}</p>
  </div>
</template>

<script>
export default {
  // 声明接收的属性(必须和父组件传递的属性名一致)
  props: ['username'] 
}
</script>

踩坑提醒:

  • props 是 “单向数据流”:子组件不能直接修改 props 的值(就像孩子不能直接改父母给的东西),如果要改,得先复制到 data 里
  • 命名规范:父组件用 kebab-case(如user-name),子组件 props 用 camelCase(如userName),Vue 会自动转换

三、子传父:用 $emit 触发事件

子组件给父组件传数据,更像是 “喊一声”—— 子组件通过$emit触发一个事件,父组件监听这个事件并接收数据。

1. 子组件如何发数据?

子组件里有个按钮,点击后要把自己的数据传给父组件:

vue

<template>
  <div class="child">
    <button @click="sendMsg">告诉父组件</button>
  </div>
</template>

<script>
export default {
  data() {
    return {
      childMsg: '爸爸我想吃西瓜' // 子组件要传递的数据
    }
  },
  methods: {
    sendMsg() {
      // 第一个参数:事件名(自定义),第二个参数:要传递的数据
      this.$emit('tellParent', this.childMsg)
    }
  }
}
</script>

2. 父组件如何接数据?

父组件监听子组件触发的事件:

vue

<template>
  <div class="parent">
    <!-- 监听子组件的tellParent事件,用getMsg方法接收数据 -->
    <Child @tellParent="getMsg" />
    <p>子组件说:{{ childMessage }}</p>
  </div>
</template>

<script>
import Child from './Child.vue'
export default {
  components: { Child },
  data() {
    return {
      childMessage: '' // 存储子组件传来的数据
    }
  },
  methods: {
    getMsg(msg) {
      // msg就是子组件传递过来的数据
      this.childMessage = msg
    }
  }
}
</script>

踩坑提醒:

  • 事件名要一致:子组件$emit('xxx'),父组件就要@xxx监听
  • 别忘记传参数:刚开始我经常只写this.$emit('tellParent'),结果父组件接收不到数据,原来漏了第二个参数!

四、实战小案例:父子组件双向互动

结合上面两种方式,做一个简单的互动:父组件给子组件传一个初始值,子组件修改后再传给父组件显示。

完整代码可以参考我之前练习的例子:

  • 父组件通过 props 给子组件传初始消息
  • 子组件通过按钮点击,用 $emit 把修改后的数据传回父组件
  • 父组件更新数据后,子组件会自动同步(因为 props 是响应式的)

这个过程就像父子对话:

  1. 父:“今天天气不错”(props 传值)
  2. 子:“是啊,适合出去玩”($emit 传值)
  3. 父:“那我们下午去公园”(props 更新,子组件同步显示)

五、总结

学了这么久才发现,Vue 的组件通信其实很像现实中的人际交流 —— 有来有回,有规有矩。刚开始总觉得难,其实是因为没搞懂 “props 是父给子,$emit 是子喊父” 这个核心逻辑。

作为前端新手,我觉得没必要一开始就纠结复杂的通信方式(比如 Vuex、Pinia),先把最基础的父子组件通信练熟,再逐步学习更高级的用法。如果大家有和我一样的困惑,建议多写几个小案例,亲手调试一下数据流向,比光看教程有用多了~

最后,欢迎大家在评论区分享自己学习组件通信时踩过的坑,让我们一起避坑成长!

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐