为什么 Vue3 封装 Table 组件丢失 expose 方法呢?

news/2024/11/19 21:46:23/

在实际开发中,我们通常会将某些常见组件进行二次封装,以便更好地实现特定的业务需求。然而,在封装 Table 组件时,遇到一个问题:Table 内部暴露的方法,在封装之后的组件获取不到。

代码展示为:

const MyTable = defineComponent({name: 'MyTable',props: ElTable.props,emits: Object.keys(ElTable.emits || {}),setup(props, { slots, attrs, expose }) {const tableRef = ref<InstanceType<typeof ElTable>>();return () => (<div class='table-container'><ElTableref={tableRef}{...props}{...attrs}v-slots={slots}>{slots.default && slots.default()}</ElTable></div>);},
});

在 Element Plus 的 ElTable 组件中,有很多暴露的方法,如下:

官方文档:Table 表格 | Element Plus

但使用上面封装的 MyTable 打印组件实例时,只有 table 本身的方法:

下面简单分析一下原因。 

1. expose 未正确定义或调用

原因分析:

在 Vue 3 中,expose 用于暴露子组件的方法和属性,使父组件能够访问和操作它们。如果封装ElTable 组件,但是没有正确定义 expose 或者没有通过 ref 正确引用子组件实例,那么 expose 的方法无法生效。

如果在 setup 中使用 expose API 或者 expose 的位置不对,那么暴露的方法就无法通过 ref 访问到。🌰:

expose({setCurrentRow: tableRef.value?.setCurrentRow, // 错误:此时 tableRef.value 还可能为 nullclearSelection: tableRef.value?.clearSelection // 错误
});

解决方法:确保在 setup 中正确使用 expose 并且在暴露方法时,确保 tableRef 已经指向 ElTable 的实例。

2. ElTable 组件实例未传递给 tableRef

原因分析:

封装代码中,ElTable 内部 expose 的方法(例如:setCurrentRow、clearSelection 等)可能会因为 ref 没有正确透传而丢失。Vue3 中,ref 的默认行为不能直接传递组件的 expose 方法到父组件中(本质)。

解决方法:手动暴露,确保 ElTable 组件通过 ref 绑定到 tableRef。

3. 组件生命周期中的调用顺序问题

原因分析:

expose 需要在 setup 函数中定义,而 tableRef 需要在组件挂载后才能被正确引用。如果在组件生命周期的某个不合适的时间调用 expose,比如,在 setup 函数之外或者组件渲染之前,可能导致tableRef 无法正确指向组件实例,从而无法暴露方法。

解决方法:使用 nextTick 来确保组件渲染完成后再执行某些操作。

综上,代码如下:

import { defineComponent, ref } from 'vue';
import { ElTable } from 'element-plus';export default defineComponent({name: 'MyTable',props: ElTable.props,emits: Object.keys(ElTable.emits || {}),setup(props, { attrs, slots, expose }) {const tableRef = ref<InstanceType<typeof ElTable>>();// 确保暴露方法时,tableRef 已经引用了正确的实例expose({setCurrentRow: (...args: Parameters<InstanceType<typeof ElTable>['setCurrentRow']>) =>tableRef.value?.setCurrentRow(...args),clearSelection: (...args: Parameters<InstanceType<typeof ElTable>['clearSelection']>) =>tableRef.value?.clearSelection(...args),});return () => (<div class="table-container"><ElTable ref={tableRef} {...props} {...attrs} v-slots={slots}>{slots.default && slots.default()}</ElTable></div>);}
});

现在再看一下 组件实例,已经存在了需要的方法。

注意,在 table 内部存在很多暴露的方法,要想让我们封装的 MyTable 和 ElTable 可以通用,那么需要将方法全部暴露出来:

export default defineComponent({name: 'MyTable',props: ElTable.props,emits: Object.keys(ElTable.emits || {}),setup(props, { attrs, slots, expose }) {const tableRef = ref<InstanceType<typeof ElTable>>();const ExposedMethods = ["clearSelection","getSelectionRows","toggleRowSelection","toggleAllSelection","toggleRowExpansion",// ...];// 将方法透传const exposedMethods: Record<string, Function> = {};ExposedMethods.forEach(method => {exposedMethods[method] = (...args: any[]) => {return tableRef.value?.[method](...args);};});// 使用 expose 透传所有方法expose(exposedMethods);return () => (<div class="table-container"><ElTable ref={tableRef} {...props} {...attrs} v-slots={slots}>{slots.default && slots.default()}</ElTable></div>);}
});

现在,所有的方法均存在,后续可以直接使用我们封装的 MyTable 组件。 

 4. 注意

有一个坑,不能将 expose 放在 onMounted 内部执行,为什么呢?

onMounted(() => {const exposedMethods: Record<string, Function> = {};ExposedMethods.forEach(method => {exposedMethods[method] = (...args: any[]) => {return tableRef.value?.[method](...args);};});// 使用 expose 透传所有方法expose(exposedMethods);
});

1. expose 在 setup 函数内部调用时,会立即暴露方法或属性给外部访问。 如果将 expose 放入 onMounted 中,setup 函数的执行已经结束,因此暴露的方法不会被 Vue 视为暴露的实例方法。

2. onMounted 是一个生命周期钩子函数,它会在组件挂载后执行,但此时 Vue 的响应式系统和父组件的访问已经设定好了,因此暴露的方法不再能正确传递。


http://www.ppmy.cn/news/1548331.html

相关文章

芯原科技嵌入式面试题及参考答案

Linux 相关驱动怎么写? 在 Linux 中编写驱动主要有以下步骤。 首先,需要了解设备的硬件特性。这包括设备的工作原理、寄存器地址和功能、中断号等信息。例如,对于一个简单的 GPIO 设备,要知道其数据寄存器、方向寄存器的位置以及读写操作的规则。 然后是模块的初始化部分。…

Python re 模块:正则表达式的强大工具

文章目录 Python re 模块&#xff1a;正则表达式的强大工具导入 re 模块基本匹配方法re.match()re.search()re.findall()re.finditer() 替换操作re.sub() 分割字符串re.split() 捕获组和非捕获组捕获组非捕获组 常用模式符号实际应用示例验证电子邮件格式提取 URL 预定义字符简…

【企业级分布式系统】ZooKeeper集群

文章目录 Zookeeper 概述Zookeeper 定义Zookeeper 工作机制Zookeeper 特点Zookeeper 数据结构Zookeeper 选举机制 部署 Zookeeper 集群准备 3 台服务器作为 Zookeeper 集群节点1. 安装前准备关闭防火墙安装 JDK下载安装包 2. 安装 Zookeeper修改配置文件拷贝配置好的 Zookeeper…

网络技术-访问控制列表(ACL)

访问控制列表&#xff08;Access Control Lists&#xff0c;ACL&#xff09;是一种基于包过滤的访问控制技术&#xff0c;它可以根据设定的条件对接口上的数据包进行过滤&#xff0c;允许其通过或丢弃。 备注&#xff1a;ACL被广泛地应用于路由器和三层交换机。 ACL的使用涉及…

HarmonyOS ArkUI(基于ArkTS) 开发布局 (上)

一 ArkUI(基于ArkTS)概述 基于ArkTS的声明式开发范式的方舟开发框架是一套开发极简、高性能、支持跨设备的UI开发框架&#xff0c;提供了构建应用UI所必需的能力 点击详情 特点 开发效率高&#xff0c;开发体验好 代码简洁&#xff1a;通过接近自然语义的方式描述UI&#x…

MySQL技巧之跨服务器数据查询:基础篇-A数据库与B数据库查询合并--封装到存储过程中

MySQL技巧之跨服务器数据查询&#xff1a;基础篇-A数据库与B数据库查询合并–封装到存储过程中 我们的最终目的是什么&#xff1f;当然的自动执行这些合并操作&#xff01; 上一篇 MySQL技巧之跨服务器数据查询&#xff1a;基础篇-A数据库与B数据库查询合并 我们已经知道怎么合…

沃丰科技出海客服解决方案:为中国企业出海保驾护航

一、引言 随着全球化的不断深入和“一带一路”倡议的推进&#xff0c;越来越多的中国企业开始走出国门&#xff0c;拓展海外市场。然而&#xff0c;在海外市场拓展的过程中&#xff0c;客户服务作为企业与客户之间的桥梁&#xff0c;其重要性不言而喻。一个优秀的出海客服解决…

python爬虫快速获取商品历史价格信息

在编写Python爬虫以获取商品历史价格信息时&#xff0c;我们通常会使用一些流行的库&#xff0c;比如requests来发送网络请求&#xff0c;以及BeautifulSoup来解析HTML页面。下面是一个简单的示例&#xff0c;展示了如何使用这些工具来爬取某个商品的历史价格信息。 首先&#…