基于Vue3 + elementPlus dialog封装,可用js调用弹窗,支持异步操作
定义dialog.vue
文件
<template>
<el-dialog :title="title" v-model="visible">
<slot>
<!-- 渲染纯js窗体 -->
<div v-html="contentBody" v-if="contentBody"></div>
</slot>
<template #footer>
<span class="dialog-footer">
<el-button @click="handleCancel" :disabled="confirmLoading">
{{cancelText}}</el-button>
<el-button
type="primary"
:loading="confirmLoading"
@click="$emit('confirm')"
>{{ confirmText }}</el-button>
</span>
</template>
</el-dialog>
</template>
<script setup>
import { computed, defineProps, defineEmits, ref } from "vue";
// 纯js调用时必须,不然解析不出<el-dialog></el-dialog>、<el-button />
import { ElDialog, ElButton } from "element-plus";
const props = defineProps({
modelValue: false,
title: "",
cancelText: {
type: String,
default: "取消"
},
confirmText: {
type: String,
default: "确定"
},
loading: false,
contentBody: null
});
const emits = defineEmits(["update:modelValue", "cancel", "close"]);
// 纯js实例调用改变loading属性
const _loading = ref(false);
const confirmLoading = computed(() => {
return props.loading || _loading.value;
});
const visible = computed({
get () {
return props.modelValue;
},
set (val) {
emits("update:modelValue", val);
}
});
// methods
const handleCancel = () => {
emits("cancel");
visible.value = false;
};
const showLoading = () => {
_loading.value = true;
};
const hideLoading = () => {
_loading.value = false;
};
// 暴露给纯js实例调用,可在实例中使用instance._instance.exposed查询到
defineExpose({ showLoading, hideLoading });
</script>
定义dialog.js
文件
import { createApp } from 'vue'
import Dialog from "./dialog.vue";
export default({ title, content, onCancel, onConfirm }) => {
const mountNode = document.createElement('div')
const instance = createApp(Dialog, {
title,
modelValue: true,
contentBody: content,
onCancel: () => {
instance.unmount(mountNode);
document.body.removeChild(mountNode);
onCancel && onCancel()
},
onConfirm: async () => {
if (onConfirm) {
await onConfirm()
}
instance.unmount(mountNode);
document.body.removeChild(mountNode);
}
})
document.body.appendChild(mountNode)
instance.mount(mountNode)
// 显示dialog loading
instance.showLoading = () => {
instance._instance.exposed.showLoading()
};
// 关闭dialog loading
instance.hideLoading = () => {
instance._instance.exposed.hideLoading()
}
return instance
}
标签组件使用
<template>
<Dialog
title="标题"
:loading="confirmLoading"
confirmText="保存"
@confirm="handleConfirm"
>
<div>我是内容</div>
</Dialog>
</template>
<script setup>
import {ref} from "vue";
import Dialog from "@/components/dialog.vue";
const confirmLoading = ref(false);
// methods
const handleConfirm = () => {
confirmLoading.value = true;
setTimeout(()=>{
confirmLoading.value = false;
},1500)
};
</script>
纯js调用
<template>
<el-button @click="handleOpenDialog">open</el-button>
</template>
<script setup>
import DialogHandle from "@/components/dialog.js";
const handleOpenDialog = () => {
const dialog = DialogHandle({
title: "操作确认",
content: "<div>是否确定删除数据?</div>",
onConfirm: () => {
return new Promise(async (resolve) => {
dialog.showLoading();
setTimeout(() => {
dialog.hideLoading();
resolve();
}, 1500);
});
},
});
};
</script>