面试题:Vue 父子组件之间传值有哪些方式?

在 Vue 中,父子组件之间的数据传递是构建可维护应用的基础。以下是父子组件传值的主要方式,涵盖 Vue 2 和 Vue 3 的通用实践。


一、父组件 → 子组件:通过 Props

这是最标准、最常用的向下传递数据的方式。

1. 父组件传递数据

<!-- ParentComponent.vue -->
<template>
  <ChildComponent 
    :title="parentTitle" 
    :count="count" 
    :is-active="isActive"
  />
</template>

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

export default {
  components: { ChildComponent },
  data() {
    return {
      parentTitle: 'Hello from Parent',
      count: 10,
      isActive: true
    }
  }
}
</script>

2. 子组件接收并定义 Props

<!-- ChildComponent.vue -->
<template>
  <div>
    <h2>{{ title }}</h2>
    <p>Count: {{ count }}</p>
    <p>Active: {{ isActive }}</p>
  </div>
</template>

<script>
export default {
  props: {
    title: {
      type: String,
      required: true
    },
    count: {
      type: Number,
      default: 0
    },
    isActive: {
      type: Boolean,
      default: false
    }
  }
}
</script>

特点

  • 单向数据流:子组件不能直接修改 props(会报警告)。
  • 支持类型校验、默认值、是否必填等。

二、子组件 → 父组件:通过 $emit 触发事件

子组件通过 $emit 触发自定义事件,父组件通过 v-on 监听。

1. 子组件触发事件

<!-- ChildComponent.vue -->
<template>
  <button @click="notifyParent">
    点击通知父组件
  </button>
</template>

<script>
export default {
  methods: {
    notifyParent() {
      // 触发自定义事件,并传递数据
      this.$emit('update-count', this.count + 1)
      this.$emit('status-change', { active: false, time: Date.now() })
    }
  }
}
</script>

2. 父组件监听事件

<!-- ParentComponent.vue -->
<template>
  <div>
    <ChildComponent 
      @update-count="handleUpdate" 
      @status-change="handleStatus"
    />
    <p>当前计数: {{ count }}</p>
  </div>
</template>

<script>
export default {
  data() {
    return {
      count: 0
    }
  },
  methods: {
    handleUpdate(newCount) {
      this.count = newCount
    },
    handleStatus(payload) {
      console.log('状态变更:', payload)
    }
  }
}
</script>

特点

  • 实现子到父的“回调”机制。
  • 支持传递任意类型的数据。

三、结合 v-model 实现双向绑定(语法糖)

v-model:value + @input 的语法糖,常用于表单组件。

1. 父组件使用 v-model

<template>
  <CustomInput v-model="message" />
  <!-- 等价于 -->
  <!-- <CustomInput :modelValue="message" @update:modelValue="message = $event" /> -->
</template>

2. 子组件配合 modelValueupdate:modelValue

<!-- CustomInput.vue -->
<template>
  <input 
    :value="modelValue" 
    @input="$emit('update:modelValue', $event.target.value)"
  />
</template>

<script>
export default {
  props: ['modelValue'],
  emits: ['update:modelValue'] // 显式声明触发的事件(Vue 3 推荐)
}
</script>

Vue 3 扩展:支持多个 v-model

<UserEditor 
  v-model:name="userName" 
  v-model:age="userAge" 
/>

四、通过 ref 获取子组件实例(直接访问)

父组件可以通过 ref 直接调用子组件的方法或访问其数据(谨慎使用)。

1. 子组件暴露方法

<!-- ChildComponent.vue -->
<script>
export default {
  methods: {
    focusInput() {
      this.$refs.input?.focus()
    }
  }
}
</script>

2. 父组件调用子组件方法

<!-- ParentComponent.vue -->
<template>
  <ChildComponent ref="childRef" />
  <button @click="focusChild">
    聚焦子组件输入框
  </button>
</template>

<script>
export default {
  methods: {
    focusChild() {
      this.$refs.childRef.focusInput()
    }
  }
}
</script>

⚠️ 注意:破坏了组件的封装性,应尽量避免,仅用于特定操作(如表单聚焦、动画触发)。


五、使用 .sync 修饰符(Vue 2,Vue 3 已废弃)

Vue 2 中用于实现双向绑定的语法糖(Vue 3 中被 v-model 扩展取代)。

<!-- Vue 2 -->
<ChildComponent :title.sync="parentTitle" />
<!-- 等价于 -->
<ChildComponent 
  :title="parentTitle" 
  @update:title="parentTitle = $event" 
/>

❌ Vue 3 中已移除 .sync,推荐使用 v-model 或自定义参数的 v-model


总结:父子传值方式对比

方式方向适用场景推荐指数
props父 → 子传递配置、数据、状态⭐⭐⭐⭐⭐
$emit子 → 父子组件通知父组件状态变化⭐⭐⭐⭐⭐
v-model双向表单组件、需要双向同步的场景⭐⭐⭐⭐
ref父 → 子(方法调用)父组件调用子组件方法⭐⭐(谨慎使用)
.sync双向(Vue 2)Vue 2 中的双向绑定⭐(Vue 3 已废弃)

最佳实践:优先使用 props + $emit 实现数据流,保持组件的高内聚、低耦合

THE END
喜欢就支持一下吧
点赞9 分享