自定义vue3函数式弹窗

vue文件,用于编写弹窗组件样式

html 复制代码
<template>
    <div class='custom_pop_container'>
        <!-- 遮罩层 -->
        <div class='mask_layer'></div>
        <!-- 弹窗内容 -->
        <div class="custom_pop_content">
            <!-- 标题 -->
            <div class="custom_pop_title">
                <img :src="iconUrl" class="pop_icon_box">
                {{ title }}
            </div>
            <!-- 内容 -->
            <div class="custom_pop_content_text">{{ content }}</div>
            <!-- 按钮 -->
            <div class="custom_pop_content_buttons">
                <button class="cancel_button button_style" @click="onCancel">{{ cancelButtonText }}</button>
                <button class="confirm_button button_style" @click="onConfirm">{{ confirmButtonText }}</button>
            </div>
        </div>
    </div>
</template>
<script setup lang='ts'>
// 响应式数据
import { getAssetsFile } from '@/utils/utils';
import { ref, reactive, computed, watch } from 'vue'
interface IProps {
    title: string;
    content: string;
    iconUrl?: string;
    confirmButtonText?: string;
    cancelButtonText?: string;
    showFooter?: boolean;
    onConfirm?: () => void;
    onCancel?: () => void;
}
const props = withDefaults(defineProps<IProps>(), {
    content: '',
    iconUrl: getAssetsFile('chat/pop_icon.png'),
    confirmButtonText: '确认',
    cancelButtonText: '取消',
    showFooter: true,
    onConfirm: () => { },
    onCancel: () => { },
})
</script>


<style scoped lang='scss'>
.custom_pop_container {
    width: 100vw;
    height: 100vh;
    position: fixed;
    top: 0;
    left: 0;
    z-index: 1000;

    .mask_layer {
        width: 100%;
        height: 100%;
        background-color: rgba(0, 0, 0, 0.4);
        position: absolute;
        top: 0;
        left: 0;
    }

    .custom_pop_content {
        width: 418px;
        background-color: #F8F9FB;
        border-radius: 12px;
        padding: 24px 20px 20px 20px;
        position: absolute;
        top: 50%;
        left: 50%;
        transform: translate(-50%, -50%);

        .custom_pop_title {
            display: flex;
            align-items: center;
            font-weight: 500;
            font-size: 16px;
            color: #303133;
            line-height: 24px;
            margin-bottom: 20px;

            .pop_icon_box {
                width: 16px;
                height: 16px;
                object-fit: cover;
                margin-right: 4px;
            }
        }

        .custom_pop_content_text {
            font-weight: 400;
            font-size: 14px;
            color: #303133;
            line-height: 22px;
        }

        .custom_pop_content_buttons {
            display: flex;
            justify-content: flex-end;
            column-gap: 12px;
            margin-top: 40px;

            .button_style {
                display: inline-flex;
                justify-content: center;
                align-items: center;
                width: 68px;
                height: 32px;
                padding: 8px 15px;
                font-size: 14px;
                font-weight: 500;
                line-height: 1;
                border-radius: 4px;
                border: 1px solid;
                cursor: pointer;
                outline: none;
                transition: 0.1s;
                appearance: none;
                -webkit-appearance: none;
                box-sizing: border-box;
            }

            .cancel_button {
                color: #606266;
                background-color: #fff;
                border-color: #dcdfe6;

                &:hover {
                    color: #409eff;
                    border-color: #c6e2ff;
                    background-color: #ecf5ff;
                }

                &:active {
                    color: #3a8ee6;
                    border-color: #3a8ee6;
                    background-color: #d9ecff;
                }
            }

            .confirm_button {
                color: #fff;
                background-color: #409eff;
                border-color: #409eff;

                &:hover {
                    background-color: #66b1ff;
                    border-color: #66b1ff;
                }

                &:active {
                    background-color: #3a8ee6;
                    border-color: #3a8ee6;
                }
            }
        }
    }
}
</style>

ts文件,把弹窗组件渲染出来

typescript 复制代码
import CustomPopCom from './CustomPopCom.vue';
import { createVNode, render } from 'vue';
let customPopDom = null;
export const useCustomPop = (userOptions: any) => {
    let options = {
        ...userOptions,
    }
    options.onCancel = () => {
        userOptions.onCancel && userOptions.onCancel();  //用户的关闭函数
        closeCustomPop();
    }
    options.onConfirm = () => {
        userOptions.onConfirm && userOptions.onConfirm();  //用户的确认函数
        closeCustomPop();
    }
    // 获取到虚拟dom
    const vnode = createVNode(CustomPopCom, options);
    customPopDom = document.createElement('div');
    render(vnode, customPopDom);
    // 渲染到body中
    document.body.appendChild(customPopDom);
}
export const closeCustomPop = () => {
    customPopDom && document.body.removeChild(customPopDom);
}

在vue文件中使用

typescript 复制代码
useCustomPop({
        title: '删除会话',
        content: '删除后无法恢复,是否继续删除?',
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        onConfirm: () => {
            deleteAgentChat({
                user_id: userStore.userInfo?.id,
                session_id: item.session_id,
            }).then(res => {
                ElMessage.success("删除会话成功");
                getGroupChatListFun();
            })
        },
    })
相关推荐
ZC跨境爬虫24 分钟前
跟着MDN学HTML_day_48:(Node接口)
前端·javascript·ui·html·音视频
PieroPc2 小时前
CAMWATCH — 局域网摄像头监控系统 Fastapi + html
前端·python·html·fastapi·监控
巴巴博一3 小时前
2026 最新:Trae / Cursor 一键接入 taste-skill 完整教程(让 AI 前端告别“AI 味”)
前端·ai·ai编程
kyriewen3 小时前
半夜三点线上崩了,AI替我背了锅——用AI排错,五分钟定位三年老bug
前端·javascript·ai编程
kyriewen3 小时前
我让 AI 当了 24 小时全年无休的“毒舌考官”
前端·ci/cd·ai编程
hexu_blog4 小时前
vue+java实现图片批量压缩
java·前端·vue.js
IT_陈寒4 小时前
为什么你应该学习JavaScript?
前端·人工智能·后端
lifejump4 小时前
Empire(帝国)CMS 7.5 XSS注入
前端·安全·xss
无风听海4 小时前
OAuth 2.0 前端通道与后端通道深入剖析
前端·oauth