| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198 |
- <template>
- <view v-if="visible" class="ss-confirm">
- <!-- 遮罩层 - 模糊背景 -->
- <view class="confirm-mask" @click="handleMaskClick"></view>
- <!-- 弹窗内容 -->
- <view class="confirm-content" :style="contentStyle">
- <!-- 头部信息 - 可选 -->
- <view v-if="showHeader" class="confirm-header">
- <slot name="header">
- <view class="header-title">{{ title }}</view>
- </slot>
- </view>
- <view class="header-line" v-if="showHeader"></view>
- <!-- 主要内容区域 - 通过slot传入 -->
- <view class="confirm-body">
- <slot></slot>
- </view>
- <!-- 底部按钮 -->
- <view class="confirm-bottom">
- <SsBottom :buttons="bottomButtons" @button-click="handleBottomClick" />
- </view>
- </view>
- </view>
- </template>
- <script setup>
- import { computed } from 'vue'
- import SsBottom from '@/components/SsBottom/index.vue'
- // Props定义
- const props = defineProps({
- // 弹窗显示状态
- visible: {
- type: Boolean,
- default: false
- },
- // 弹窗标题
- title: {
- type: String,
- default: '确认'
- },
- // 是否显示头部
- showHeader: {
- type: Boolean,
- default: true
- },
- // 弹窗宽度
- width: {
- type: [String, Number],
- default: '600rpx'
- },
- // 弹窗高度
- height: {
- type: [String, Number],
- default: '500rpx'
- },
- // 弹窗最大高度
- // maxHeight: {
- // type: [String, Number],
- // default: '500rpx'
- // },
- // 底部按钮配置
- bottomButtons: {
- type: Array,
- default: () => [
- { text: '取消', type: 'default' },
- { text: '确认', type: 'primary' }
- ]
- },
- // 点击遮罩是否关闭
- maskClosable: {
- type: Boolean,
- default: true
- }
- })
- // 事件定义
- const emit = defineEmits(['update:visible', 'close', 'button-click', 'mask-click'])
- // 计算弹窗样式
- const contentStyle = computed(() => {
- const style = {}
- // 处理宽度
- if (typeof props.width === 'number') {
- style.width = props.width + 'rpx'
- } else {
- style.width = props.width
- }
- // 处理高度
- if (props.height !== 'auto') {
- if (typeof props.height === 'number') {
- style.height = props.height + 'rpx'
- } else {
- style.height = props.height
- }
- }
-
- return style
- })
- /**
- * 处理遮罩点击
- */
- // const handleMaskClick = () => {
- // emit('mask-click')
- // if (props.maskClosable) {
- // emit('update:visible', false)
- // emit('close')
- // }
- // }
- /**
- * 处理底部按钮点击
- */
- const handleBottomClick = (button, index) => {
- emit('button-click', button, index)
- }
- </script>
- <style lang="scss" scoped>
- .ss-confirm {
- position: fixed;
- top: 0;
- left: 0;
- right: 0;
- bottom: 0;
- z-index: 9999;
- display: flex;
- flex-direction: column;
- }
- // 遮罩层
- .confirm-mask {
- position: absolute;
- top: 0;
- left: 0;
- right: 0;
- bottom: 0;
- backdrop-filter: blur(4rpx); // 只要模糊效果,不要颜色
- -webkit-backdrop-filter: blur(41rpxrpx);
- }
- // 弹窗内容
- .confirm-content {
- position: absolute;
- top: 50%;
- left: 50%;
- transform: translate(-50%, -50%);
- background: #f2f3f4;
- border-radius: 10rpx;
- overflow: hidden;
- display: flex;
- flex-direction: column;
- box-shadow: 12rpx 10rpx 5rpx rgba(0, 0, 0, 0.3);
- // 宽高通过 :style 动态设置
- }
- // 头部信息
- .confirm-header {
- padding-top: 41rpx;
- padding-bottom: 20rpx;
- border-bottom: 1rpx solid #f2f3f4;
- .header-title {
- font-size: 42rpx;
- color: #333;
- text-align: center;
- }
- }
- .header-line {
- width: calc(100% - 104rpx);
- height: 1rpx;
- background: #e6e6e6;
- margin: 0 auto;
- }
- // 主要内容区域
- .confirm-body {
- flex: 1;
- overflow: hidden;
- display: flex;
- flex-direction: column;
- }
- // 底部按钮
- .confirm-bottom {
- position: relative;
- border-top: 1rpx solid #eee;
- }
- </style>
|