index.vue 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. <template>
  2. <view v-if="visible" class="ss-confirm">
  3. <!-- 遮罩层 - 模糊背景 -->
  4. <view class="confirm-mask" @click="handleMaskClick"></view>
  5. <!-- 弹窗内容 -->
  6. <view class="confirm-content" :style="contentStyle">
  7. <!-- 头部信息 - 可选 -->
  8. <view v-if="showHeader" class="confirm-header">
  9. <slot name="header">
  10. <view class="header-title">{{ title }}</view>
  11. </slot>
  12. </view>
  13. <view class="header-line" v-if="showHeader"></view>
  14. <!-- 主要内容区域 - 通过slot传入 -->
  15. <view class="confirm-body">
  16. <slot></slot>
  17. </view>
  18. <!-- 底部按钮 -->
  19. <view class="confirm-bottom">
  20. <SsBottom :buttons="bottomButtons" @button-click="handleBottomClick" />
  21. </view>
  22. </view>
  23. </view>
  24. </template>
  25. <script setup>
  26. import { computed } from 'vue'
  27. import SsBottom from '@/components/SsBottom/index.vue'
  28. // Props定义
  29. const props = defineProps({
  30. // 弹窗显示状态
  31. visible: {
  32. type: Boolean,
  33. default: false
  34. },
  35. // 弹窗标题
  36. title: {
  37. type: String,
  38. default: '确认'
  39. },
  40. // 是否显示头部
  41. showHeader: {
  42. type: Boolean,
  43. default: true
  44. },
  45. // 弹窗宽度
  46. width: {
  47. type: [String, Number],
  48. default: '600rpx'
  49. },
  50. // 弹窗高度
  51. height: {
  52. type: [String, Number],
  53. default: '500rpx'
  54. },
  55. // 弹窗最大高度
  56. // maxHeight: {
  57. // type: [String, Number],
  58. // default: '500rpx'
  59. // },
  60. // 底部按钮配置
  61. bottomButtons: {
  62. type: Array,
  63. default: () => [
  64. { text: '取消', type: 'default' },
  65. { text: '确认', type: 'primary' }
  66. ]
  67. },
  68. // 点击遮罩是否关闭
  69. maskClosable: {
  70. type: Boolean,
  71. default: true
  72. }
  73. })
  74. // 事件定义
  75. const emit = defineEmits(['update:visible', 'close', 'button-click', 'mask-click'])
  76. // 计算弹窗样式
  77. const contentStyle = computed(() => {
  78. const style = {}
  79. // 处理宽度
  80. if (typeof props.width === 'number') {
  81. style.width = props.width + 'rpx'
  82. } else {
  83. style.width = props.width
  84. }
  85. // 处理高度
  86. if (props.height !== 'auto') {
  87. if (typeof props.height === 'number') {
  88. style.height = props.height + 'rpx'
  89. } else {
  90. style.height = props.height
  91. }
  92. }
  93. return style
  94. })
  95. /**
  96. * 处理遮罩点击
  97. */
  98. // const handleMaskClick = () => {
  99. // emit('mask-click')
  100. // if (props.maskClosable) {
  101. // emit('update:visible', false)
  102. // emit('close')
  103. // }
  104. // }
  105. /**
  106. * 处理底部按钮点击
  107. */
  108. const handleBottomClick = (button, index) => {
  109. emit('button-click', button, index)
  110. }
  111. </script>
  112. <style lang="scss" scoped>
  113. .ss-confirm {
  114. position: fixed;
  115. top: 0;
  116. left: 0;
  117. right: 0;
  118. bottom: 0;
  119. z-index: 9999;
  120. display: flex;
  121. flex-direction: column;
  122. }
  123. // 遮罩层
  124. .confirm-mask {
  125. position: absolute;
  126. top: 0;
  127. left: 0;
  128. right: 0;
  129. bottom: 0;
  130. backdrop-filter: blur(4rpx); // 只要模糊效果,不要颜色
  131. -webkit-backdrop-filter: blur(41rpxrpx);
  132. }
  133. // 弹窗内容
  134. .confirm-content {
  135. position: absolute;
  136. top: 50%;
  137. left: 50%;
  138. transform: translate(-50%, -50%);
  139. background: #f2f3f4;
  140. border-radius: 10rpx;
  141. overflow: hidden;
  142. display: flex;
  143. flex-direction: column;
  144. box-shadow: 12rpx 10rpx 5rpx rgba(0, 0, 0, 0.3);
  145. // 宽高通过 :style 动态设置
  146. }
  147. // 头部信息
  148. .confirm-header {
  149. padding-top: 41rpx;
  150. padding-bottom: 20rpx;
  151. border-bottom: 1rpx solid #f2f3f4;
  152. .header-title {
  153. font-size: 42rpx;
  154. color: #333;
  155. text-align: center;
  156. }
  157. }
  158. .header-line {
  159. width: calc(100% - 104rpx);
  160. height: 1rpx;
  161. background: #e6e6e6;
  162. margin: 0 auto;
  163. }
  164. // 主要内容区域
  165. .confirm-body {
  166. flex: 1;
  167. overflow: hidden;
  168. display: flex;
  169. flex-direction: column;
  170. }
  171. // 底部按钮
  172. .confirm-bottom {
  173. position: relative;
  174. border-top: 1rpx solid #eee;
  175. }
  176. </style>