diy-message-box(开箱即用)

模仿element-plus里的ElMessage.confirm实现自定义消息确认弹窗

技术栈:vue3+js

使用方式:

import DiyMessageBox from "./index.js";

DiyMessageBox.confirm("确认操作", "你确定要执行此操作吗?")
    .then(() => {
        console.log("用户确认操作");
    })
    .catch((error) => {
        console.log(error.message);
    });

主要代码:

index.js

import { createVNode, render } from "vue";
import DiyMessageBoxComp from "./DiyMessageBox.vue";

// 创建一个单例的容器元素
const container = document.createElement("div");
document.body.appendChild(container); //挂载组件到 body

const DiyMessageBox = {
    confirm(title = "提示", message = "", options = {}) {
        return new Promise((resolve, reject) => {
            let isCleaned = false;
            // 清除弹窗
            const cleanUp = () => {
                if (isCleaned) return;
                isCleaned = true;
                render(null, container);
            };

            const handleError = (action, errorMessage, rejectFn) => {
                try {
                    rejectFn();
                } catch (error) {
                    console.error(`${action}处理异常:`, error);
                } finally {
                    cleanUp();
                }
            };

            try {
                const vnode = createVNode(DiyMessageBoxComp, {
                    title,
                    message,
                    ...options,
                    onConfirm: () => {
                        try {
                            console.log("confirm");
                            resolve();
                        } catch (error) {
                            console.error("确认按钮处理函数异常:", error);
                        } finally {
                            cleanUp();
                        }
                    },
                    onCancel: () =>
                        handleError("取消按钮", "用户取消操作", () =>
                            reject(new Error("用户取消操作"))
                        ),
                    onClose: () =>
                        handleError("关闭按钮", "用户关闭弹窗", () =>
                            reject(new Error("用户关闭弹窗"))
                        ),
                });

                render(vnode, container);
            } catch (error) {
                console.error("创建或渲染虚拟节点时出错:", error);
                cleanUp();
                reject(error);
            }
        });
    },
};

export default DiyMessageBox;

DiyMessageBox.vue(该组件可以自由发挥,实现任何样式)

<template>
    <div class="diy-message-box" @click="close">
        <div class="diy-message-box__wrapper" @click.stop>
            <div class="diy-message-box__header">
                <el-icon class="header-icon"><WarningFilled /></el-icon>
                <span class="header-text">{
  
  { props.title }}</span>
                <el-icon class="header-icon close" @click="close"
                    ><CloseBold
                /></el-icon>
            </div>
            <div class="diy-message-box__content">
                <p>{
  
  { props.message }}</p>
            </div>
            <div class="diy-message-box__footer">
                <button class="confirm" @click="handleConfirm">
                    {
  
  { props.confirmButtonText }}
                </button>
                <button class="cancel" @click="handleCancel">
                    {
  
  { props.cancelButtonText }}
                </button>
            </div>
        </div>
    </div>
</template>
<script setup>
import { defineProps, defineEmits, onMounted, onUnmounted } from "vue";
import { CloseBold, WarningFilled } from "@element-plus/icons-vue";

// 定义组件的属性
const props = defineProps({
    title: {
        type: String,
        default: "提示",
    },
    message: {
        type: String,
        default: "",
    },
    confirmButtonText: {
        type: String,
        default: "确认",
    },
    cancelButtonText: {
        type: String,
        default: "取消",
    },
});

// 定义组件的事件
const emits = defineEmits(["confirm", "cancel", "close"]);

// 处理确认按钮点击事件
const handleConfirm = () => {
    console.log("handleConfirm is called");
    emits("confirm");
};

// 处理取消按钮点击事件
const handleCancel = () => {
    emits("cancel");
};
// 处理关闭事件
const close = () => {
    emits("close");
};
// 处理键盘按下事件,当按下 Esc 键时关闭弹窗
const handleKeydown = (e) => {
    if (e.key === "Escape") close();
};

onMounted(() => window.addEventListener("keydown", handleKeydown));
onUnmounted(() => window.removeEventListener("keydown", handleKeydown));
// 导出组件的方法
defineExpose({});
</script>
<style scoped lang="less">
.diy-message-box {
    position: absolute;
    top: 0;
    left: 0;
    width: 100vw;
    height: 100vh;
    z-index: 1024;
    .diy-message-box__wrapper {
        position: fixed;
        top: 50%;
        left: 50%;
        transform: translate(-50%, -50%);
        width: 316px;
        height: 164px;

        background: linear-gradient(
            270deg,
            rgba(38, 51, 67, 0.7) 16%,
            rgba(16, 29, 47, 0.8) 100%
        );
        .diy-message-box__header {
            display: grid;
            grid-template-columns: 20px auto 20px;
            column-gap: 4px;
            align-items: center;
            padding: 5px 8px;
            background: linear-gradient(
                89deg,
                #152a35 0%,
                rgba(62, 123, 213, 0.8) 21%,
                rgba(32, 39, 68, 0) 72%,
                rgba(32, 39, 68, 0) 92%
            );
            border-radius: 0px 0px 0px 0px;
            border: 1px solid;
            border-image: linear-gradient(
                    88deg,
                    rgba(213, 242, 253, 0.3),
                    rgba(62, 123, 213, 1),
                    rgba(213, 242, 253, 0.2),
                    rgba(213, 242, 253, 0)
                )
                1 1;
            .header-text {
                font-weight: bold;
                font-size: 14px;
                color: #ffffff;
                line-height: 20px;
            }
            .header-icon {
                font-size: 16px;
            }
            .header-icon.close {
                cursor: pointer;
            }
        }

        .diy-message-box__content {
            text-align: center;
            font-weight: bold;
            font-size: 16px;
            color: #ffffff;
            min-height: 20px;
            max-height: 200px;
            overflow-y: auto;
            padding: 30px 0;
        }

        .diy-message-box__footer {
            display: flex;
            justify-content: center;
            gap: 30px;
            padding-bottom: 20px;
            button {
                display: flex;
                align-items: center;
                justify-content: center;
                cursor: pointer;
                box-sizing: border-box;
                width: 84px;
                height: 30px;
                font-weight: 500;
                font-size: 14px;
                white-space: nowrap;
                color: #ffffff;
                line-height: 20px;
                border-radius: 4px 4px 4px 4px;
            }
            .confirm {
                background: var(--button-highlight-bg);
                box-shadow: inset 0px 0px 16px 0px #67a2ff;
            }
            .cancel {
                background: rgba(1, 26, 68, 0.6);
                border: 1px solid rgba(255, 255, 255, 0.6);
            }
        }
    }
}
</style>

效果图:

posted @   YAY_tyy  阅读(2)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
点击右上角即可分享
微信分享提示