自定义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();
            })
        },
    })
相关推荐
roamingcode35 分钟前
前端 AI Agent 多智能体协作架构:从对抗式排查到工作流解耦
前端·人工智能·架构·agent·team
蓝莓味的口香糖2 小时前
【vue】初始化 Vue 项目
前端·javascript·vue.js
aikongmeng2 小时前
【Ai】Claude Code 初始化引导
javascript
光影少年2 小时前
数组去重方法
开发语言·前端·javascript
我命由我123452 小时前
浏览器的 JS 模块化支持观察记录
开发语言·前端·javascript·css·html·ecmascript·html5
weixin_443478513 小时前
Flutter第三方常用组件包之路由管理
前端·javascript·flutter
武藤一雄3 小时前
C# 异步回调与等待机制
前端·microsoft·设计模式·微软·c#·.netcore
啥都不懂的小小白3 小时前
前端CSS入门详解
前端·css
林恒smileZAZ3 小时前
前端大屏适配方案:rem、vw/vh、scale 到底选哪个?
开发语言·前端·css·css3
QQ5110082854 小时前
基于区块链的个人医疗咨询挂号信息系统vue
前端·vue.js·区块链