custom-modal.vue 2.84 KB
<template>
	<view class="custom-modal" v-if="show">
		<view class="modal-mask" @click="onMaskClick"></view>
		<view class="modal-content">
			<view class="modal-header" v-if="title">
				<text class="modal-title">{{ title }}</text>
			</view>
			<view class="modal-body">
				<rich-text v-if="isHtml" :nodes="content"></rich-text>
				<text v-else class="modal-text">{{ content }}</text>
			</view>
			<view class="modal-footer">
				<button class="btn-cancel" @click="onCancel" v-if="showCancel">{{ cancelText }}</button>
				<button class="btn-confirm" @click="onConfirm" v-if="showConfirm">{{ confirmText }}</button>
			</view>
		</view>
	</view>
</template>

<script setup>
import { ref } from 'vue'

const props = defineProps({
	title: {
		type: String,
		default: ''
	},
	content: {
		type: String,
		default: ''
	},
	isHtml: {
		type: Boolean,
		default: false
	},
	showCancel: {
		type: Boolean,
		default: true
	},
	showConfirm: {
		type: Boolean,
		default: true
	},
	cancelText: {
		type: String,
		default: '取消'
	},
	confirmText: {
		type: String,
		default: '确定'
	},
	maskCloseable: {
		type: Boolean,
		default: true
	}
})

const emit = defineEmits(['cancel', 'confirm'])

const show = ref(false)

function onCancel() {
	show.value = false
	emit('cancel')
}

function onConfirm() {
	show.value = false
	emit('confirm')
}

function onMaskClick() {
	if (props.maskCloseable) {
		show.value = false
	}
}

// 对外暴露的方法
function open() {
	show.value = true
}

function close() {
	show.value = false
}

defineExpose({ open, close })
</script>

<style lang="scss" scoped>
.custom-modal {
	position: fixed;
	top: 0;
	left: 0;
	right: 0;
	bottom: 0;
	z-index: 9999;
	display: flex;
	align-items: center;
	justify-content: center;
}

.modal-mask {
	position: absolute;
	top: 0;
	left: 0;
	right: 0;
	bottom: 0;
	background: rgba(0, 0, 0, 0.5);
}

.modal-content {
	position: relative;
	width: 600rpx;
	max-width: 85%;
	background: #fff;
	border-radius: 24rpx;
	overflow: hidden;
	animation: modalIn 0.2s ease;
}

@keyframes modalIn {
	from {
		opacity: 0;
		transform: scale(0.9);
	}
	to {
		opacity: 1;
		transform: scale(1);
	}
}

.modal-header {
	padding: 32rpx 30rpx 0;
	text-align: center;
}

.modal-title {
	font-size: 32rpx;
	font-weight: 600;
	color: #333;
}

.modal-body {
	padding: 30rpx;
	max-height: 60vh;
	overflow-y: auto;
}

.modal-text {
	font-size: 28rpx;
	color: #666;
	line-height: 1.6;
	text-align: center;
	white-space: pre-wrap;
	word-break: break-word;
}

.modal-footer {
	display: flex;
	padding: 0 30rpx 30rpx;
	gap: 24rpx;
	justify-content: center;
}

.btn-cancel,
.btn-confirm {
	flex: 1;
	height: 80rpx;
	line-height: 80rpx;
	font-size: 30rpx;
	border-radius: 40rpx;
	margin: 0;
	padding: 0;
	border: none;
}

.btn-cancel {
	background: #fff;
	color: #AD181F;
	border: 2rpx solid #AD181F;
}

.btn-confirm {
	background: #AD181F;
	color: #fff;
}
</style>