携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第22天,点击查看活动详情
在项目开发中,父子组件之间的交互是基本的操作之一了,而在 Vue3 的 setup 语法糖中,父子组件的参数传递与 Vue2 有所不同。下面就将几种传递方式整理,方便理解记忆。
Vue2 中,props:[] 以及 emit() 进行父子组件交互,而 Vue3 中需要使用:
- defineProps
- defineEmits
父传子
父组件:
<Child :name=""></Child>
子组件:
<template>
<h1>{{props.name}}</h1>
</template>
<script setup>
import { defineProps } from 'vue'
const props = defineProps({
name:{
type:String,
default:"子组件的默认值"
}
})
const emit = defineEmits(["emitchange"])
</script>
子传父
触发了事件emitName,给父组件传递参数val
子组件:
emit("eventName", val)
父组件:
<Child @eventName="func"></Child>
父组件调用子组件的方法
在父组件调用子组件的地方,添加ref属性:ref="ChildDOM"
ChildDOM.value.doSomething();
遇到的问题
场景1:
子组件向父组件传递事件时,发出警告:Extraneous non-emits event listeners (selectMeth) were passed to component but could not be automatically inherited because component renders fragment or text root nodes
这种警告属于vue3.0的代码规范,因为传递事件的子组件没有根节点,在父组件中会被渲染为代码片段
要解决这个问题,有两种方式:
- 子组件的
<template>中设置根标签,正常方式emit即可 - 子组件的
<template>中没有根标签,不修改<template>,则需要声明 defineEmits(["emitchange"])(其中 emitchange 是发送的事件名称),再执行 emit
使用defineEmits语法糖的方法来创建自定义事件,defineEmits中的参数为数组形式,可传递多个事件名称。
场景2:
父组件改变传入数据的值,子组件中无法响应数据的的变化
这里就要能够区分 ref 与 toRef 的不同:
-
ref 是对传入数据的拷贝,原始值改变并不影响当前数据
-
toRef 是对传入数据的引用,原始值改变会影响当前数据
使用方法:
const name = toRef(props, 'name');
或者:
const { name } = toRefs(props);
注意 toRef 与 toRefs 的写法有所不同
除此之外还有 provide inject 来实现组件之间的传递