181 lines
3.4 KiB
Vue
181 lines
3.4 KiB
Vue
<template>
|
||
<transition name="popup-fade">
|
||
<div class="global-popup" v-show="visible">
|
||
<!-- 遮罩层 -->
|
||
<div class="popup-mask" @click="maskClose && handleClose"></div>
|
||
<!-- 弹窗主体 -->
|
||
<div class="popup-main" :style="{ width: width + 'px' }">
|
||
<!-- 标题 -->
|
||
<div class="popup-title" v-if="title">{{ title }}</div>
|
||
<!-- 自定义内容插槽 -->
|
||
<slot name="content"></slot>
|
||
<!-- 默认内容 -->
|
||
<div class="popup-content" v-if="!$slots.content">{{ content }}</div>
|
||
<!-- 底部按钮 -->
|
||
<div class="popup-footer" v-if="showBtn">
|
||
<button class="btn cancel" @click="handleCancel" v-if="showCancelBtn">
|
||
{{ cancelText }}
|
||
</button>
|
||
<button class="btn confirm" @click="handleConfirm">
|
||
{{ confirmText }}
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</transition>
|
||
</template>
|
||
|
||
<script>
|
||
export default {
|
||
name: "GlobalPopup",
|
||
props: {
|
||
// 是否显示弹窗
|
||
visible: {
|
||
type: Boolean,
|
||
default: false,
|
||
},
|
||
// 弹窗标题
|
||
title: {
|
||
type: String,
|
||
default: "",
|
||
},
|
||
// 弹窗内容
|
||
content: {
|
||
type: String,
|
||
default: "",
|
||
},
|
||
// 弹窗宽度(px)
|
||
width: {
|
||
type: [Number, String],
|
||
default: 300,
|
||
},
|
||
// 是否显示按钮
|
||
showBtn: {
|
||
type: Boolean,
|
||
default: true,
|
||
},
|
||
// 是否显示取消按钮
|
||
showCancelBtn: {
|
||
type: Boolean,
|
||
default: true,
|
||
},
|
||
// 取消按钮文字
|
||
cancelText: {
|
||
type: String,
|
||
default: "取消",
|
||
},
|
||
// 确认按钮文字
|
||
confirmText: {
|
||
type: String,
|
||
default: "确认",
|
||
},
|
||
// 点击遮罩是否关闭
|
||
maskClose: {
|
||
type: Boolean,
|
||
default: true,
|
||
},
|
||
},
|
||
methods: {
|
||
// 通用关闭方法
|
||
handleClose() {
|
||
this.$emit("update:visible", false);
|
||
},
|
||
// 取消按钮回调
|
||
handleCancel() {
|
||
this.handleClose();
|
||
this.$emit("cancel");
|
||
},
|
||
// 确认按钮回调
|
||
handleConfirm() {
|
||
this.handleClose();
|
||
this.$emit("confirm");
|
||
},
|
||
},
|
||
};
|
||
</script>
|
||
|
||
<style scoped>
|
||
/* Vue2 过渡动画类名 */
|
||
.popup-fade-enter,
|
||
.popup-fade-leave-to {
|
||
opacity: 0;
|
||
}
|
||
.popup-fade-enter-active,
|
||
.popup-fade-leave-active {
|
||
transition: all 0.3s ease;
|
||
}
|
||
|
||
/* 弹窗容器:固定定位+居中 */
|
||
.global-popup {
|
||
position: fixed;
|
||
top: 0;
|
||
left: 0;
|
||
right: 0;
|
||
bottom: 0;
|
||
z-index: 9999; /* 高层级保证不被覆盖 */
|
||
display: flex;
|
||
justify-content: center;
|
||
align-items: center;
|
||
}
|
||
|
||
/* 遮罩层 */
|
||
.popup-mask {
|
||
position: absolute;
|
||
top: 0;
|
||
left: 0;
|
||
right: 0;
|
||
bottom: 0;
|
||
background: rgba(0, 0, 0, 0.5);
|
||
}
|
||
|
||
/* 弹窗主体 */
|
||
.popup-main {
|
||
background: #fff;
|
||
border-radius: 8px;
|
||
padding: 16px;
|
||
position: relative;
|
||
z-index: 1;
|
||
box-sizing: border-box;
|
||
}
|
||
|
||
/* 标题样式 */
|
||
.popup-title {
|
||
font-size: 18px;
|
||
font-weight: bold;
|
||
text-align: center;
|
||
margin-bottom: 16px;
|
||
}
|
||
|
||
/* 内容样式 */
|
||
.popup-content {
|
||
font-size: 14px;
|
||
line-height: 1.5;
|
||
margin-bottom: 24px;
|
||
text-align: center;
|
||
}
|
||
|
||
/* 底部按钮容器 */
|
||
.popup-footer {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
}
|
||
|
||
/* 按钮样式 */
|
||
.btn {
|
||
padding: 8px 16px;
|
||
border: none;
|
||
border-radius: 4px;
|
||
font-size: 14px;
|
||
cursor: pointer;
|
||
flex: 1;
|
||
margin: 0 4px;
|
||
}
|
||
.cancel {
|
||
background: #f5f5f5;
|
||
color: #333;
|
||
}
|
||
.confirm {
|
||
background: #007aff;
|
||
color: #fff;
|
||
}
|
||
</style> |