vue3父子组件传值defineProps、defineEmits、defineExpose

一、前言

本文介绍父子组件传值defineProps、defineEmits、defineExpose

二、语法

在 script setup 中必须使用 defineProps 和 defineEmits API 来声明 props 和 emits ,它们具备完整的类型推断并且在 script setup 中是直接可用的

2.1、defineProps

适用于父组件向子组件传递属性

2.1.1、子组件

    // 定义Props
    const props = defineProps<{
        result: number,
        name: string
    }>()

2.1.2、父组件

<Detail name="结果" :result="1"></Detail>

2.2、带默认值的defineProps

适用于带默认值的Props,经测试不能与defineProps在同一组件同时定义。

2.2.1、子组件

    interface IProps {
        labels?: string[]
        result: number,
        name:string     
    }

    // 定义带默认值的Props
    const defaultProps = withDefaults(defineProps<IProps>(), {
        name: 'hello',
        result:0,
        labels: () => ['one', 'two']
    })

2.2.2、父组件

<!-- 没传的Props会使用子组件的默认值 -->
<Detail name="结果"></Detail>

2.3、defineEmits

适用于父组件向子组件传递方法

2.3.1、子组件

    <button @click="btnAdd">添加</button>
    <hr />
    <button @click="btnReset">重置</button>
    <hr />
    // 定义Emits
    const emits = defineEmits<{
        (e: 'add', id: number): void
        (e: 'reset', value: number): void
    }>()

    const btnAdd = () => {
        emits('add',2)
    }
    const btnReset = () => {
        emits("reset",0)
    }

2.3.2、父组件

<!-- 传入Emits -->
<Detail @add="add" @reset="reset"></Detail>
const result = ref<number>(0);

const add = (num:number)=>{
    result.value+=num
}

const reset = (num:number)=>{
    result.value = num
}

2.4、defineExpose

适用于子组件向父组件暴露方法和属性,父组件通过子组件示例进行调用。

2.4.1、子组件

    // 定义Expose
    const exposeStr = ref<string>("")
    defineExpose({
        exposeStr
    })

2.4.2、父组件:

 <!-- 传入Props和Emits -->
<Detail ref="detail"></Detail>
// 必须跟组件ref保持一致
const detail = ref()

setTimeout (() => {
    detail.value.exposeStr = "exposeStr"
},1000)

三、完整代码

3.1、子组件:detail.vue

<template>
  <div>
    <!-- {{props.name}} - {{props.result}} -->
    <hr />
    {{defaultProps.name}} - {{defaultProps.result}} - {{defaultProps.labels}}
    <hr />
    <button @click="btnAdd">添加</button>
    <hr />
    <button @click="btnReset">重置</button>
    <hr />
    {{exposeStr}}
  </div>
</template>

<script setup lang="ts">
    import { ref,defineProps ,defineEmits,defineExpose} from "vue"

    // 定义Props
    // const props = defineProps<{
    //     result: number,
    //     name: string
    // }>()

    interface IProps {
        labels?: string[]
        result: number,
        name:string     
    }

    // 定义带默认值的Props
    const defaultProps = withDefaults(defineProps<IProps>(), {
        name: 'hello',
        result:0,
        labels: () => ['one', 'two']
    })

    // 定义Emits
    const emits = defineEmits<{
        (e: 'add', id: number): void
        (e: 'reset', value: number): void
    }>()

    const btnAdd = () => {
        emits('add',2)
    }
    const btnReset = () => {
        emits("reset",0)
    }

    // 定义Expose
    const exposeStr = ref<string>("")
    defineExpose({
        exposeStr
    })

</script>
<style lang="scss" scoped></style>

3.2、父组件:main.vue

<template>
    <div>
        <!-- 传入Props和Emits -->
        <Detail ref="detail" name="结果" :result="result" @add="add" @reset="reset"></Detail>
    </div>
</template>

<script setup lang="ts">
import Detail from './detail.vue'

import {ref} from 'vue'

const result = ref<number>(0);

const add = (num:number)=>{
    result.value+=num
}

const reset = (num:number)=>{
    result.value = num
}

// 必须跟子组件ref名保持一致
const detail = ref()
setTimeout (() => {
    // 调用子组件属性并修改值
    detail.value.exposeStr = "exposeStr"
},1000)
</script>

posted @ 2022-08-24 19:32  gaozejie  阅读(7899)  评论(1编辑  收藏  举报