Element Plus封装选择数据弹窗技巧

在Vue3项目中,我们使用了Element Plus的ElMessageBox组件来实现一个自定义的选择弹窗。这个弹窗可以集成任何自定义组件并提供数据选择功能,适用于多选或单选的场景。以下是该功能的核心设计思路和实现流程:

功能介绍

该功能的目标是动态创建一个选择弹窗,用户可以通过自定义组件进行数据选择。弹窗中展示的组件必须暴露一个名为getSelectionData的方法,用于返回用户选中的数 据。通过传递参数,开发者可以灵活地控制弹窗的行为和数据传递。

主要功能点

参数传递:

title: 弹窗的标题,默认为传入的title或options.title。 component: 要展示的自定义组件。 componentProps: 可选的组件属性,通过此属性可以传递给自定义组件。 tip: 可选提示,用于提醒用户在提交前进行数据选择。

弹窗配置:

multiple: 是否支持多选,默认单选。 queryParams: 查询参数,提供给自定义组件使用。 onOk: 提交回调,选择的数据将传递给此回调函数。 onBeforeOk: 提交前的钩子函数,可以进行数据验证,返回true表示通过验证。

弹窗行为:

弹窗内的组件通过ref引用绑定,便于获取选中的数据。 用户确认选择后,会检查是否有选择数据,如果没有,则显示提示消息(ElMessage.warning)。 提交前,如果存在onBeforeOk回调函数,将会异步执行并判断是否可以提交。如果没有该回调,直接调用onOk。 弹窗可以显示加载状态,防止用户多次点击确认。

自定义组件要求:

被引用的组件需要暴露一个getSelectionData方法,用于获取用户选择的数据。

封装代码

定义组件

使用

类型提示

源码

ts 复制代码
import { ElMessage, ElMessageBox } from 'element-plus';

type CreateSelectDialogParams = {
  title: string;
  component: any;
  componentProps?: Record<string, any>;
  tip?: string;
};

type DialogOption<T> = {
  title?: string;
  multiple?: boolean; // 多选单选
  queryParams?: Record<string, any>; // 查询参数
  onOk?: (data: T) => void;
  onBeforeOk?: (data: T) => Promise<boolean>;
};

/**
 * 创建选择弹窗
 * @description component组件必须暴露一个getSelectionData方法
 */
export const createSelectDialog = <T>(params: CreateSelectDialogParams) => {
  return function (options: DialogOption<T>) {
    const { multiple = false, onOk, onBeforeOk, queryParams } = options;
    const DialogTableRef = ref<any>();
    ElMessageBox({
      title: params.title || options.title,
      message: () =>
        h(params.component, {
          ref: (e: any) => (DialogTableRef.value = e),
          multiple: multiple,
          queryParams: queryParams,
          ...params.componentProps
        }),
      showCancelButton: true,
      customStyle: { maxWidth: '1000px' },
      beforeClose: async (action, instance, done) => {
        if (action === 'confirm') {
          const data = DialogTableRef.value?.getSelectionData();
          if (!data.length) {
            return ElMessage.warning(params.tip || '请选择数据');
          }
          if (onBeforeOk) {
            try {
              instance.confirmButtonLoading = true;
              const flag = await onBeforeOk(data);
              if (flag) {
                done();
                setTimeout(() => {
                  instance.confirmButtonLoading = false;
                }, 300);
              }
            } catch (error) {
              instance.confirmButtonLoading = false;
            }
          } else {
            onOk?.(data);
            done();
          }
        } else {
          done();
        }
      }
    });
  };
};
相关推荐
Danny_FD24 分钟前
Vue2 + Node.js 快速实现带心跳检测与自动重连的 WebSocket 案例
前端
uhakadotcom25 分钟前
将next.js的分享到twitter.com之中时,如何更新分享卡片上的图片?
前端·javascript·面试
韦小勇25 分钟前
el-table 父子数据层级嵌套表格
前端
奔赴_向往27 分钟前
为什么 PWA 至今没能「掘进」主流?
前端
小小愿望27 分钟前
微信小程序开发实战:图片转 Base64 全解析
前端·微信小程序
掘金安东尼30 分钟前
2分钟创建一个“不依赖任何外部库”的粒子动画背景
前端·面试·canvas
电商API大数据接口开发Cris30 分钟前
基于 Flink 的淘宝实时数据管道设计:商品详情流式处理与异构存储
前端·数据挖掘·api
小小愿望32 分钟前
解锁前端新技能:让JavaScript与CSS变量共舞
前端·javascript·css
程序员鱼皮34 分钟前
爆肝2月,我的 AI 代码生成平台上线了!
java·前端·编程·软件开发·项目
天生我材必有用_吴用1 小时前
一文搞懂 useDark:Vue 项目中实现深色模式的正确姿势
前端·vue.js