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

news2024/11/23 16:50:25

在实际开发中,我们通常会将某些常见组件进行二次封装,以便更好地实现特定的业务需求。然而,在封装 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'>
        <ElTable
          ref={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 还可能为 null
  clearSelection: 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.coloradmin.cn/o/2244432.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

项目-摄像

树莓派摄像头使用方法 Camera教程 https://www.raspi.cc/index.php?cread&id53&page1 nanopc-t4 ​https://www.raspi.cc/index.php?cread&id53&page1 摄像头型号 Raspberry Pi Camera Rev 1.3 检测故障 dmesg | grep -i mipi piNanoPC-T4:~$ dmesg | …

【ArcGIS微课1000例】0127:计算城市之间的距离

本文讲述,在ArcGIS中,计算城市(以地级城市为例)之间的距离,效果如下图所示: 一、数据准备 加载配套实验数据包中的地级市和行政区划矢量数据(订阅专栏后,从私信查收数据),如下图所示: 二、计算距离 1. 计算邻近表 ArcGIS提供了计算点和另外点之间距离的工具:分析…

解决python import ddddocr报错DLL load failed while...的办法

目录 1. DLL1.1 DLL是什么1.2 为什么会出现这个 2. 如何解决2.1 安装Microsoft Visual C Redistributable推荐</sup>2.2 安装或更新onnxruntime库2.3 检查环境变量 在Python中导入ddddocr模块的时候遇到“DLL load failed”错误, 所以记录一下解决过程。 1. DLL 1.1 DL…

All-in-one Notion 介绍

Notion 是一款集笔记、知识管理、任务规划和协作于一体的工具&#xff0c;它以高度的灵活性和可自定义的工作空间而闻名。它适合个人和团队使用&#xff0c;能够帮助用户高效管理生活、学习和工作。以下是 Notion 的一些主要特点&#xff1a; 1. 多功能工作区 Notion 将笔记、…

Linux-第2集-打包压缩 zip、tar WindowsLinux互传

欢迎来到Linux第2集&#xff0c;这一集我会非常详细的说明如何在Linux上进行打包压缩操作&#xff0c;以及解压解包 还有最最重要的压缩包的网络传输 毕竟打包压缩不是目的&#xff0c;把文件最终传到指定位置才是目的 由于打包压缩分开讲没有意义&#xff0c;并且它们俩本来…

Unity脚本基础规则

Unity脚本基础规则 如何在Unity中创建一个脚本文件&#xff1f; 在Project窗口中的Assets目录下&#xff0c;选择合适的文件夹&#xff0c;右键&#xff0c;选择第一个Create&#xff0c;在新出现的一栏中选择C# Script&#xff0c;此时文件夹内会出现C#脚本图标&#xff0c;…

[Qt platform plugin问题] Could not load the Qt platform plugin “xcb“

Qt platform plugin 是 Qt 应用程序启动时加载的插件。不同的平台有不同的插件。 常见的插件有:linuxfb Wayland xcb 简单来说就是启动一个GUI程序, 离不开这些插件.选择其中一个就好 出现这个问题要么就是没有插件&#xff0c;要么就是插件依赖的库没有。 要么就是插件选则的…

MySql 索引视图存储变量

要求 一&#xff1a; 学生表:Student(Sno&#xff0c;Sname&#xff0c;Ssex &#xff0c;Sage, Sdept) 学号&#xff0c;姓名&#xff0c;性别&#xff0c;年龄&#xff0c;所在系 Sno为主键 课程表:Course(Cno&#xff0c;Cname) 课程号&#xff0c;课程名 Cno为主键 学生…

高阶云服务-ELB+AS

ELBAS 弹性负载均衡弹性伸缩 原来1台web服务器不满足相应&#xff0c;现部署多台提供相同服务&#xff1b; 由于多个服务器多个ip该如何提供给应用呢&#xff1f; 引申出负载均衡&#xff08;HAProxy&#xff0c;LVS01四层&#xff0c;Nginx七层&#xff09; 防单点故障做主备…

集群聊天服务器(13)redis环境安装和发布订阅命令

目录 环境安装订阅redis发布-订阅的客户端编程环境配置客户端编程 功能测试 环境安装 sudo apt-get install redis-server 先启动redis服务 /etc/init.d/redis-server start默认在6379端口上 redis是存键值对的&#xff0c;还可以存链表、数组等等复杂数据结构 而且数据是在…

SpringBoot 集成 Sharding-JDBC(一):数据分片

在深入探讨 Sharding-JDBC 之前&#xff0c;建议读者先了解数据库分库分表的基本概念和应用场景。如果您还没有阅读过相关的内容&#xff0c;可以先阅读我们之前的文章&#xff1a; 关系型数据库海量数据存储策略-CSDN博客 这篇文章将帮助您更好地理解分库分表的基本原理和实现…

芋道启用undertown

芋道使用的是tomcat, 可以替换为性能更好的undertown 1.maven配置 1.1在yudao-dependencies模块下yudao-spring-boot-starter-web 和yudao-spring-boot-starter-websocket排除spring-boot-starter-tomcat 添加 <exclusions><exclusion><groupId>org.spring…

(Linux 入门) 基本指令、基本权限

目录 一、什么是操作系统 二、基础指令 01. ls 指令 02. pwd命令 03.mkdir 04. touch指令 05.rmdir指令 && rm 指令 06.man指令&#xff08;重要&#xff09; 07 cat 08.cp指令 09 mv指令 10 alias 指令 11.more指令 12.head指令 13.less指令 14.时间相…

贴代码框架PasteForm特性介绍之select,selects,lselect和reload

简介 PasteForm是贴代码推出的 “新一代CRUD” &#xff0c;基于ABPvNext&#xff0c;目的是通过对Dto的特性的标注&#xff0c;从而实现管理端的统一UI&#xff0c;借助于配套的PasteBuilder代码生成器&#xff0c;你可以快速的为自己的项目构建后台管理端&#xff01;目前管…

【AI+教育】一些记录@2024.11.16

《万字长文&#xff0c;探讨关于ChatGPT的五个最核心问题》 万字长文&#xff0c;探讨关于ChatGPT的五个最核心问题关于 ChatGPT 铺天盖地的信息让人无所适从。本文则试图提炼出五个关键问题&#xff1a;如何理解这次范式突破&#xff0c;未来能达到的技术天花板&#xff0c;行…

基于vue框架的的图书在线销售系统设计2503xPC端(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。

系统程序文件列表 项目功能&#xff1a;用户,图书分类,图书信息,入库信息 开题报告内容 基于Vue框架的图书在线销售系统设计开题报告 一、研究背景与意义 随着互联网技术的不断发展和普及&#xff0c;电子商务已成为现代商业的重要组成部分。图书作为知识和文化的载体&#…

android:taskAffinity 对Activity退出时跳转的影响

android:taskAffinity 对Activity跳转的影响 概述taskAffinity 的工作机制taskAffinity对 Activity 跳转的影响一个实际的开发问题总结参考 概述 在 Android 开发中&#xff0c;任务栈&#xff08;Task&#xff09;是一个核心概念。它决定了应用程序的 Activity 如何相互交互以…

Android15之解决:Dex checksum does not match for dex:framework.jar问题(二百三十九)

简介&#xff1a; CSDN博客专家、《Android系统多媒体进阶实战》一书作者 新书发布&#xff1a;《Android系统多媒体进阶实战》&#x1f680; 优质专栏&#xff1a; Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 优质专栏&#xff1a; 多媒体系统工程师系列【…

SpringBoot(7)-Swagger

目录 一、是什么 二、SpringBoot集成Swagger 三、配置Swagger 3.1 配置文档信息 3.2 配置扫描接口 3.3 配置Swagger开关 3.4 配置API分组 3.5 实体配置 四、常用注解 五、总结 一、是什么 是一款API框架&#xff0c;API文档和API定义同步更新&#xff0c;可以在线测…

小程序19-微信小程序的样式和组件介绍

在小程序中不能使用 HTML 标签&#xff0c;也就没有 DOM 和 BOM&#xff0c;CSS 也仅支持部分选择器 小程序提供了 WXML 进行页面结构的编写&#xff0c;WXSS 进行页面的样式编写 WXML 提供了 view、text、image、navigator等标签构建页面结构&#xff0c;小程序中标签称为组件…