youdas/components/youdas-container/page-popup.vue
2025-06-21 23:03:06 +08:00

229 lines
5.0 KiB
Vue
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!-- 通用弹出组件 -->
<template>
<view v-if="state.visible" class="popup-container">
<view class="popup-mask"></view>
<view class="popup-content">
<!-- 标题区域 -->
<view v-if="state.title" class="popup-header">
<text class="popup-title">{{ state.title }}</text>
<!-- <view class="popup-close" @click="close">×</view> -->
</view>
<!-- 内容区域 -->
<view class="popup-body">
<text v-if="state.content" class="popup-content-text">{{ state.content }}</text>
<slot></slot>
</view>
<!-- 底部按钮区域 -->
<view class="popup-footer">
<button class="popup-btn popup-btn--cancel" @click="handleCancel">
{{ state.cancelText || '取消' }}
</button>
<button class="popup-btn popup-btn--confirm" @click="handleConfirm">
{{ state.confirmText || '确定' }}
</button>
</view>
</view>
</view>
</template>
<script setup>
import { reactive, ref } from 'vue';
// 使用reactive状态存储弹窗的各种属性
const state = reactive({
visible: false,
title: '',
content: '',
confirmText: '确定',
cancelText: '取消',
onConfirm: null,
onCancel: null
});
// 存储Promise的resolve和reject函数
const currentResolve = ref(null);
const currentReject = ref(null);
// 打开弹窗方法
const open = (options = {}) => {
state.title = options.title || '';
state.content = options.content || '';
state.confirmText = options.confirmText || '确定';
state.cancelText = options.cancelText || '取消';
state.onConfirm = options.onConfirm || null;
state.onCancel = options.onCancel || null;
state.visible = true;
currentResolve.value = null;
currentReject.value = null;
};
/**
* 异步打开弹窗方法返回Promise
* @param {String} title 标题
* @param {String} content 内容
* @param {String} confirmText 确定按钮文本
* @param {String} cancelText 取消按钮文本
* @param {Function} onConfirm 确定回调
* @param {Function} onCancel
* @returns
*/
const showModal = (title, content, confirmText = "确定", cancelText = "取消", onConfirm = null, onCancel = null) => {
return new Promise((resolve, reject) => {
open({ title, content, confirmText, cancelText, onConfirm, onCancel });
currentResolve.value = resolve;
currentReject.value = reject;
});
};
// 关闭弹窗方法
const close = () => {
state.visible = false;
// 如果有未完成的Promise取消它
if (currentReject.value) {
currentReject.value('popup-closed');
currentResolve.value = null;
currentReject.value = null;
}
};
// 处理确认
const handleConfirm = () => {
// 处理常规回调
if (typeof state.onConfirm === 'function') {
state.onConfirm();
}
// 处理Promise
if (currentResolve.value) {
currentResolve.value({ confirm: true, cancel: false });
currentResolve.value = null;
currentReject.value = null;
}
close();
};
// 处理取消
const handleCancel = () => {
// 处理常规回调
if (typeof state.onCancel === 'function') {
state.onCancel();
}
// 处理Promise
if (currentReject.value) {
// currentReject.value('cancel');
currentResolve.value({ confirm: false, cancel: true });
currentResolve.value = null;
currentReject.value = null;
}
close();
};
// 将方法暴露给父组件
defineExpose({
open,
showModal,
close
});
</script>
<style lang="scss" scoped>
.popup-container {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 999;
display: flex;
align-items: center;
justify-content: center;
.popup-mask {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.5);
}
.popup-content {
position: relative;
background-color: #fff;
border-radius: 8rpx;
box-shadow: 0 4rpx 24rpx rgba(0, 0, 0, 0.15);
overflow: hidden;
max-height: 90%;
max-width: 90%;
width: 90%;
display: flex;
flex-direction: column;
z-index: 1;
}
.popup-header {
padding: 32rpx 40rpx;
border-bottom: 1rpx solid #eee;
display: flex;
justify-content: space-between;
align-items: center;
.popup-title {
margin: 0;
font-size: 32rpx;
font-weight: 500;
color: #333;
}
.popup-close {
font-size: 40rpx;
color: #999;
}
}
.popup-body {
padding: 40rpx;
overflow-y: auto;
flex: 1;
.popup-content-text {
font-size: 28rpx;
line-height: 1.6;
color: #333;
}
}
.popup-footer {
padding: 20rpx 20rpx;
border-top: 1rpx solid #eee;
text-align: right;
display: flex;
justify-content: flex-end;
.popup-btn {
// padding: 16rpx 20rpx;
// margin-left: 20rpx;
border-radius: 8rpx;
font-size: 28rpx;
width: 200rpx;
text-align: center;
&--cancel {
background-color: #f7f7f7;
color: #666;
}
&--confirm {
background-color: #409eff;
color: white;
}
}
}
}
</style>