自定义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();
            })
        },
    })
相关推荐
To_OC36 分钟前
从 “卡死半天” 到 “打字机效果”:大模型流式输出前端实现全记录
前端·javascript·llm
rockey62743 分钟前
基于AScript的JavaScript脚本语言发布啦
javascript·c#·.net·js·script
SoaringHeart1 小时前
Flutter最佳实践:键盘辅助视图输入框天添加图片附件
前端·flutter
kyriewen2 小时前
我看完这篇安全论文——AI推荐的npm包,92%是编出来的
前端·javascript·ai编程
心中有国也有家2 小时前
AtomGit Flutter 鸿蒙客户端:Canvas 绘制进阶-路径、渐变与混合模式
android·javascript·flutter·华为·harmonyos
小心我捶你啊3 小时前
数据采集和Web解锁不是一回事,从用途到规则区分
前端·爬虫·网络协议
hunterandroid3 小时前
[鸿蒙从零到一] ArkUI 基础组件实战:Text、Image、Button 与 TextInput
前端
fsssb3 小时前
Chromium 源码学习笔记(五):一次点击,在进入 JS 之前先经历了什么?
前端
hunterandroid3 小时前
WorkManager 可靠性实战:唯一任务、重试与幂等设计
android·前端