自定义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();
            })
        },
    })
相关推荐
new code Boy1 小时前
前端全栈之路
前端
牛奶2 小时前
为什么敲几个字母就能访问网站?DNS原理大揭秘
前端·http·dns
wuhen_n2 小时前
破冰——建立我们的AI开发实验环境
前端·javascript
HelloReader2 小时前
Flutter 自适应布局一套代码适配手机和平板(十二)
前端
牛奶2 小时前
HTTP裸奔,HTTPS穿盔甲——它们有什么区别?
前端·http·https
梓言2 小时前
tailwindcss构建执行npm exec tailwindcss init -p 报错
前端
哈罗哈皮2 小时前
龙虾(openclaw)本地快速安装及使用教程
前端·aigc·ai编程
用户23115444530582 小时前
React中实现“双向绑定”效果的几种方式
前端
HelloReader2 小时前
Flutter Sliver 高级滚动打造 iOS 通讯录体验(十三)
前端