父子通信
vue2
- 父组件通过 props 将数据传递给子组件
- 子组件利用 $emit 通知父组件修改更新
单向数据流:父级props 的数据更新,会向下流动,影响子组件。这个数据流动是单向的


vue3
父传子基本思想
- 父组件中给子组件绑定属性
- 子组件内部通过props选项接收数据

子传父基本思想
- 父组件中给子组件标签通过@绑定事件
- 子组件内部通过 emit 方法触发事件

模版引用
如果父组件需要"知道这个值变化",
那这个值就不该在子组件。就需要使用父子通信,值在父组件这里。
如果父组件只需要"让你做件事",
那就用模板引用获取。
vue的初始化顺序,先beforeCreate,然后data / methods / computed / watch 初始化,再然后created
所以模板引用需要写在mounted里。
vue2
vue
<template>
<input ref="username" />
<ChildComp ref="child" />
<ChildComp v-if="showChild" ref="child" />
</template>
<script>
mounted() {
//1、普通dom元素
this.$refs.username.focus()
//2、获取子组件实例(包含:data、methods、props、$el(根 DOM)、$refs(子组件内部 ref)、computed)
console.log(this.$refs.child)
}
methods: {
openChild() {
this.showChild = true
//3、条件渲染 v-if 列表渲染 v-for 动态组件/弹窗 需要使用this.$nextTick获取
// ❌ 这里访问 this.$refs.child 可能 undefined
this.$nextTick(() => {
this.$refs.child.doSomething() // ✅ 安全
})
}
}
</script>
Vue2 的模板引用非常"强大",几乎可以随意操作子组件的内部实现,这也是 Vue3 收紧的原因。
vue3
子组件实例 默认只暴露对父可见的接口 (需要 defineExpose)
vue
获取DOM
<template>
<input ref="username" />
<button @click="focusInput">聚焦</button>
</template>
<script setup>
import { ref, onMounted } from 'vue'
const username = ref(null)
const focusInput = () => {
username.value.focus()
}
onMounted(() => {
console.log(username.value) // ✅ 已挂载的 DOM
})
</script>
获取子组件实例
<template>
<ChildComp ref="childRef" />
<button @click="openChild">打开子组件</button>
</template>
<script setup>
import { ref } from 'vue'
import ChildComp from './ChildComp.vue'
const childRef = ref(null)
const openChild = () => {
childRef.value.open() // 调用子组件暴露的方法
}
</script>
<script setup>
import { defineExpose } from 'vue'
const open = () => {
console.log('子组件打开了')
}
defineExpose({ open }) // ⚠️ 必须暴露
</script>