Vue进阶 | Vue3 setup 语法糖中实现父子组件传参

1,360 阅读2分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 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的代码规范,因为传递事件的子组件没有根节点,在父组件中会被渲染为代码片段

image.png

要解决这个问题,有两种方式:

  1. 子组件的<template> 中设置根标签,正常方式emit即可
  2. 子组件的<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 来实现组件之间的传递