vue3命令式弹窗方案

1,731 阅读1分钟

介绍

在vue3中,有很多开发环境中都需要使用弹框,传统的element-plus需要控制变量来显示隐藏,如果单文件中有多个弹窗就需要维护多个变量,这样维护起来不方便,这时候就可以考虑使用命令式弹窗方案,不足点就是表单组件需要单独创建。

一、基本实现

弹窗组件

import { createApp, h, ref } from 'vue';
import { ElDialog, ElButton } from 'element-plus';

/**
 * @param component 弹窗默认内容-插槽名为#default
 * @param props 弹窗默认内容的属性
 * @param modalProps 弹窗属性
 */
export function renderDialog(component, props, modalProps) {
  const open = ref(true);
  const loading = ref(false);
  const instance = ref();
  //dialog必须是函数式组件
  const dialog = () =>
    h(
      ElDialog,
      {
        ...modalProps,
        modelValue: open.value,
        onClosed() {
          app.unmount();
          document.body.removeChild(div);
        },
      },
      {
        default: () => h(component, { ...props, ref: instance }),
        footer: () =>
          h('div', { className: 'dialog-footer' }, [
            h(ElButton, { onClick: cancel }, () => '取 消'),
            h(
              ElButton,
              { type: 'primary', onClick: submit, loading: loading.value },
              () => '确 认'
            ),
          ]),
      }
    );
  const app = createApp(dialog);
  const div = document.createElement('div');
  document.body.appendChild(div);
  app.mount(div);
  //确认按钮
  async function submit() {
    loading.value = true;
    try {
      await instance.value?.submit?.();
      open.value = false;
    } finally {
      loading.value = false;
    }
  }
  //取消按钮
  function cancel() {
    open.value = false;
  }
}

表单组件

根据自身需求创建对应的表单组件

<script setup lang="ts">
import { reactive, ref } from 'vue';

const form = reactive({ name: '' });
const formRef = ref();
const rules = reactive({
  name: [{ required: true, message: '姓名不能为空', trigger: 'blur' }],
});
defineExpose({
  async submit() {
    await formRef.value.validate();
    return new Promise((resolve) => {
      setTimeout(() => {
        console.log('提交成功');
        resolve('提交成功');
      }, 1500);
    });
  },
});
</script>

<template>
  <el-form :model="form" ref="formRef" label-width="auto" style="max-width: 600px" :rules="rules">
    <el-form-item label="姓名" prop="name">
      <el-input v-model="form.name" />
    </el-form-item>
  </el-form>
</template>

<style scoped></style>

使用方法

import { renderDialog } from './utils/index.ts';
renderDialog(Form, {}, { title: '登录' });

总结

该方案主要是为了不在单文件中重复维护多个变量,声明式弹窗和命令式弹窗各有优势,欢迎交流补充!