defineExpose 、defineProps、defineEmits --- vue3组件间通讯1

本文介绍了Vue3中用于组件通信的三个关键宏命令:defineExpose用于子组件向父组件暴露属性和方法;defineProps用于声明和定义props,接收父组件传值;defineEmits则用于在子组件中注册和触发自定义事件,传递信息给父组件。这些宏在<scriptsetup>语法中使用,简化了父子组件间的交互。

 defineExpose 、defineProps、defineEmits 是vue3的写法并且是一个仅 <script setup> 中可用的编译宏命令,并不需要显式地导入;

defineExpose 来显式指定在 <script setup> 组件中要暴露出去的属性。

defineProps、defineEmits在vue3的非语法糖setup和在vue2中的写法是 props,emit 

defineExpose   子传父 

(用在子组件,暴露想传递的值或方法,父组件通过ref属性获取子组件暴露的)

1. 作用

defineExpose定义:用于组件通信中父级组件调用操作子组建方法和响应式属性参数能力,即子组件将值和方法传给父组件。

2. 原理

使用 <script setup> 的组件是默认关闭的——即通过模板引用或者 $parent 链获取到的组件的公开实例,不会暴露任何在 <script setup> 中声明的绑定。

那么,通过 defineExpose 编译器宏来显式指定在 <script setup> 组件中要暴露出去的属性

然后,父组件通过ref属性访问子组件

3. 实例

 父组件:

<Index ref="childeRef"></Index>

<script setup>
    import Index from "./index.vue";

    const childeRef = ref();

    function test() {
        console.log(childeRef.value.msg) // Hello World
    }

    onMounted(() => {
      let flag:boolean = true;
      let value:number= 5;
      childeRef.value.childFn(flag,value) // 调用子组件函数, 输出 6
    })

</script>

子组件:

<script setup>
    import {ref} from "vue";

    function childFn(type:boolean, data:number) {
        console.log('我是子组件');
        if(data){
           let value = data + 1;   
           return value;
        }
    }
    
    const msg = 'Hello World';
    const num = ref(0);
    
    defineExpose({ //暴露想要传递的值或方法
        msg,
        childFn,
    });
</script>

defineProps  父传子 

(用在子组件,接收父组件的传值,用来声明props)

1. 作用

它可以帮助我们在组件中自定义 props,并定义它们的数据类型和默认值。使用这个新特性,可以更加方便地管理组件的 Props 数据

2. 原理

defineProps() 宏中的参数不可以访问 <script setup>中定义的其他变量,因为在编译时整个表达式都会被移到外部的函数中,即必须在<script setup>的顶层使用,不可以在<script setup>的局部变量中引用;

3. 实例

父组件:

<templte>
   <sub-task-detail
      v-model:open="subTaskDetailVisible"
      :task-info="task"
      :sub-task-id="subTaskId"
      :tab="tabIndex"
    />
</templte>

<script setup>
    
    const subTaskDetailVisible = ref(false)
    
    const handleDetail = (row) => {
      subTaskDetailVisible.value = true
      subTaskId.value = row.id
      tabIndex.value = 1
    }

</script>

子组件:

<script setup>
import { ref, watch, onMounted, onBeforeUnmount, h } from 'vue'
import { subTaskDetail, downloadLog } from '@/api/detail'
import BigDataList from './BigDataList.vue'
import dayjs from 'dayjs'
import { useI18n } from 'vue-i18n'
import { MIGRATION_MODE, SUB_TASK_STATUS } from '@/utils/constants'

const { t } = useI18n()

const props = defineProps({
  open: Boolean,
  taskInfo: Object,
  subTaskId: [String, Number],
  tab: [String, Number]
})
//也可以let props = defineProps(['open','taskInfo','subTaskId','tab']);

onMounted(() => {
  visible.value = props.open
})

</script>

defineEmits  子传父 

(用在子组件,触发父组件的方法,并将子组件的值传递给父组件,用来声明emits)
 

1. 作用

用于在setup中注册自定义事件,方便开发者监听和绑定事件。是一个宏函数,使用时无需导入

2. 原理

不可以访问 <script setup>中定义的其他变量,因为在编译时整个表达式都会被移到外部的函数中,即defineEmits必须放在全局,否则报错。

3. 实例

父组件:

<template>

 <add-jdbc ref="addJdbcRef" @finish="finishAddJdbc" />
 
</template>

<script setup>
import { reactive, ref, computed, watch, onMounted, toRaw, h, compile } from 'vue'
import AddJdbc from '../components/AddJdbc.vue'
import { sourceClusters, targetClusters, sourceClusterDbsData, targetClusterDbsData } from '@/api/task'
 
const finishAddJdbc = (type) => {
  if (type === 'ORACLE'||type === 'MYSQL') {
    getSourceClustersData()
  } else {
    getTargetClustersData()
  }
}
</script>

子组件:

<script setup>
//defineEmits接受一个数组,元素为自定义事件名
//返回一个触发器,用于触发事件,第一个参数是具体事件名,第二个是传递的值

 emits = defineEmits([`finish`])

 const submit = () => {
    // save
    data.loading = true

    const param = {
      clusterName: data.form.name,
      dbType: data.form.dbType,
      deployType: data.form.nodes.length > 1 ? 'CLUSTER' : 'SINGLE_NODE',
      nodes: []
    }

    addJdbc(param).then((res) => {
      data.loading = false
      if (Number(res.code) === 200) {
        Message.success({ content: `Create success` })
        emits(`finish`, data.form.dbType)
      }
      close()
    })
}

### 定义与使用场景 在 C++ 中,`#define` 和 `const` 都可以用于定义常量,但它们的工作机制和适用场景存在显著差异。以下是两者的区别及使用场景的详细分析。 #### 1. 工作机制 - `#define` 是预处理指令,在编译之前进行文本替换操作[^1]。这意味着它不经过编译器类型检查,直接将宏名替换为对应的值。 - `const` 是编译时常量,遵循 C++ 的作用域规则,并且会进行严格的类型检查[^2]。 ```cpp #define MAX_VALUE 100 // #define 宏定义 const int CONST_VALUE = 100; // const 常量定义 ``` #### 2. 类型检查 - `#define` 不具备类型信息,因此无法进行类型检查。例如,`#define PI 3.14` 只是一个简单的文本替换,编译器不会验证其是否符合上下文中的类型要求。 - `const` 则具有明确的类型信息,编译器会在编译阶段检查其类型是否正确。例如,`const double PI = 3.14;` 明确指定了 PI 的类型为 `double`[^4]。 #### 3. 作用域 - `#define` 没有作用域的概念,它的作用范围从定义处开始直到文件结束[^1]。如果需要限制作用范围,必须手动取消定义(`#undef`)。 - `const` 遵循 C++ 的作用域规则,可以在局部、全局或类的作用域内定义。例如: ```cpp void func() { const int LOCAL_CONST = 10; // 局部作用域 } ``` 在函数 `func` 外部无法访问 `LOCAL_CONST`[^2]。 #### 4. 内存分配 - `#define` 不占用内存,因为它只是简单的文本替换。 - `const` 占用内存,因为它实际上是一个变量,尽管其值不可修改。可以通过取地址的方式验证这一点: ```cpp const int VALUE = 10; printf("%p\n", &VALUE); // 输出 VALUE 的地址 ``` #### 5. 使用场景 - **`#define` 的适用场景**: - 简单的文本替换,如宏定义、条件编译等。 - 定义程序配置常量,如最大用户数、最大连接数等[^3]。 - **`const` 的适用场景**: - 需要类型安全的常量定义。 - 在函数参数、返回值中传递不可修改的值。 - 定义类成员常量或全局常量[^4]。 ### 示例代码 以下代码展示了如何结合 `#define` 和 `const` 定义程序配置和版本号: ```cpp #include <stdio.h> // 使用 #define 定义程序配置常量 #define MAX_USERS 100 #define MAX_CONNECTIONS 50 int main() { // 使用 const 定义版本号 const int VERSION = 1; printf("程序配置:\n"); printf("最大用户数: %d\n", MAX_USERS); printf("最大连接数: %d\n", MAX_CONNECTIONS); printf("程序版本号: %d\n", VERSION); return 0; } ``` ### 总结 `#define` 和 `const` 各有优劣,选择时需根据具体需求权衡。如果需要简单快速的文本替换,可以选择 `#define`;如果需要类型安全、作用域控制以及更现代的编程风格,则应优先选择 `const`。
评论 3
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值