muzhiyu-ui 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (96) hide show
  1. package/README.md +202 -0
  2. package/components/muzhiyu/mu-action-sheet/mu-action-sheet.vue +335 -0
  3. package/components/muzhiyu/mu-alert/mu-alert.vue +220 -0
  4. package/components/muzhiyu/mu-back-top/mu-back-top.vue +161 -0
  5. package/components/muzhiyu/mu-badge/mu-badge.vue +150 -0
  6. package/components/muzhiyu/mu-barcode/mu-barcode.vue +100 -0
  7. package/components/muzhiyu/mu-blank/mu-blank.vue +30 -0
  8. package/components/muzhiyu/mu-bottom-nav/mu-bottom-nav.vue +331 -0
  9. package/components/muzhiyu/mu-bubble/mu-bubble.vue +316 -0
  10. package/components/muzhiyu/mu-button/mu-button.vue +431 -0
  11. package/components/muzhiyu/mu-calendar/mu-calendar.vue +429 -0
  12. package/components/muzhiyu/mu-car-input/mu-car-input.vue +209 -0
  13. package/components/muzhiyu/mu-card/mu-card.vue +317 -0
  14. package/components/muzhiyu/mu-cascader/mu-cascader.vue +336 -0
  15. package/components/muzhiyu/mu-cell/mu-cell.vue +368 -0
  16. package/components/muzhiyu/mu-checkbox/mu-checkbox.vue +116 -0
  17. package/components/muzhiyu/mu-checkbox-group/mu-checkbox-group.vue +40 -0
  18. package/components/muzhiyu/mu-code-input/mu-code-input.vue +264 -0
  19. package/components/muzhiyu/mu-collapse/mu-collapse.vue +316 -0
  20. package/components/muzhiyu/mu-color-picker/mu-color-picker.vue +466 -0
  21. package/components/muzhiyu/mu-config/index.js +34 -0
  22. package/components/muzhiyu/mu-config/mu-config.vue +54 -0
  23. package/components/muzhiyu/mu-countdown/mu-countdown.vue +338 -0
  24. package/components/muzhiyu/mu-cropper/mu-cropper.vue +415 -0
  25. package/components/muzhiyu/mu-date-picker/mu-date-picker.vue +290 -0
  26. package/components/muzhiyu/mu-datetime/mu-datetime.vue +262 -0
  27. package/components/muzhiyu/mu-divider/mu-divider.vue +229 -0
  28. package/components/muzhiyu/mu-drawer/mu-drawer.vue +172 -0
  29. package/components/muzhiyu/mu-dropdown/mu-dropdown.vue +215 -0
  30. package/components/muzhiyu/mu-dropdown-top/mu-dropdown-top.vue +243 -0
  31. package/components/muzhiyu/mu-empty/mu-empty.vue +217 -0
  32. package/components/muzhiyu/mu-fab/mu-fab.vue +324 -0
  33. package/components/muzhiyu/mu-footer/mu-footer.vue +21 -0
  34. package/components/muzhiyu/mu-form/mu-form.vue +170 -0
  35. package/components/muzhiyu/mu-grid/mu-grid.vue +95 -0
  36. package/components/muzhiyu/mu-grid-item/mu-grid-item.vue +247 -0
  37. package/components/muzhiyu/mu-html/mu-html.vue +145 -0
  38. package/components/muzhiyu/mu-icon/mu-icon.vue +822 -0
  39. package/components/muzhiyu/mu-image-grid/mu-image-grid.vue +225 -0
  40. package/components/muzhiyu/mu-image-preview/mu-image-preview.vue +286 -0
  41. package/components/muzhiyu/mu-index-list/mu-index-list.vue +381 -0
  42. package/components/muzhiyu/mu-input/mu-input.vue +570 -0
  43. package/components/muzhiyu/mu-input-number/mu-input-number.vue +193 -0
  44. package/components/muzhiyu/mu-keyboard/mu-keyboard.vue +415 -0
  45. package/components/muzhiyu/mu-list/mu-list.vue +89 -0
  46. package/components/muzhiyu/mu-loading/mu-loading.vue +124 -0
  47. package/components/muzhiyu/mu-loading-page/mu-loading-page.vue +529 -0
  48. package/components/muzhiyu/mu-loadmore/mu-loadmore.vue +26 -0
  49. package/components/muzhiyu/mu-modal/mu-modal.vue +298 -0
  50. package/components/muzhiyu/mu-navbar/mu-navbar.vue +223 -0
  51. package/components/muzhiyu/mu-nomore/mu-nomore.vue +107 -0
  52. package/components/muzhiyu/mu-notice-bar/mu-notice-bar.vue +284 -0
  53. package/components/muzhiyu/mu-notify/mu-notify.vue +202 -0
  54. package/components/muzhiyu/mu-overlay/mu-overlay.vue +94 -0
  55. package/components/muzhiyu/mu-pagination/mu-pagination.vue +330 -0
  56. package/components/muzhiyu/mu-password-input/mu-password-input.vue +119 -0
  57. package/components/muzhiyu/mu-picker/mu-picker.vue +297 -0
  58. package/components/muzhiyu/mu-popup/mu-popup.vue +297 -0
  59. package/components/muzhiyu/mu-progress/mu-progress.vue +156 -0
  60. package/components/muzhiyu/mu-pull-refresh/mu-pull-refresh.vue +54 -0
  61. package/components/muzhiyu/mu-qrcode/mu-qrcode.vue +340 -0
  62. package/components/muzhiyu/mu-qrcode/qrcode.js +2237 -0
  63. package/components/muzhiyu/mu-radio/mu-radio.vue +125 -0
  64. package/components/muzhiyu/mu-radio-group/mu-radio-group.vue +37 -0
  65. package/components/muzhiyu/mu-rate/mu-rate.vue +103 -0
  66. package/components/muzhiyu/mu-search/mu-search.vue +320 -0
  67. package/components/muzhiyu/mu-section/mu-section.vue +206 -0
  68. package/components/muzhiyu/mu-select/mu-select.vue +440 -0
  69. package/components/muzhiyu/mu-share-sheet/mu-share-sheet.vue +269 -0
  70. package/components/muzhiyu/mu-sidebar/mu-sidebar.vue +304 -0
  71. package/components/muzhiyu/mu-signature/mu-signature.vue +449 -0
  72. package/components/muzhiyu/mu-skeleton/mu-skeleton.vue +225 -0
  73. package/components/muzhiyu/mu-slider/mu-slider.vue +228 -0
  74. package/components/muzhiyu/mu-space/mu-space.vue +84 -0
  75. package/components/muzhiyu/mu-steps/mu-steps.vue +311 -0
  76. package/components/muzhiyu/mu-sticky/mu-sticky.vue +57 -0
  77. package/components/muzhiyu/mu-swipe-cell/mu-swipe-cell.vue +281 -0
  78. package/components/muzhiyu/mu-swiper/mu-swiper.vue +107 -0
  79. package/components/muzhiyu/mu-switch/mu-switch.vue +99 -0
  80. package/components/muzhiyu/mu-tabbar/mu-tabbar.vue +382 -0
  81. package/components/muzhiyu/mu-table/mu-table.vue +420 -0
  82. package/components/muzhiyu/mu-tabs/mu-tabs.vue +339 -0
  83. package/components/muzhiyu/mu-tag/mu-tag.vue +65 -0
  84. package/components/muzhiyu/mu-text-ellipsis/mu-text-ellipsis.vue +54 -0
  85. package/components/muzhiyu/mu-timeline/mu-timeline.vue +166 -0
  86. package/components/muzhiyu/mu-tips/mu-tips.vue +36 -0
  87. package/components/muzhiyu/mu-toast/mu-toast.vue +151 -0
  88. package/components/muzhiyu/mu-transfer/mu-transfer.vue +114 -0
  89. package/components/muzhiyu/mu-tree/mu-tree.vue +263 -0
  90. package/components/muzhiyu/mu-upload/mu-upload.vue +415 -0
  91. package/components/muzhiyu/mu-waterfall/mu-waterfall.vue +321 -0
  92. package/components/muzhiyu/mu-watermark/mu-watermark.vue +60 -0
  93. package/index.js +83 -0
  94. package/package.json +38 -0
  95. package/utils/index.js +600 -0
  96. package/utils/request.js +265 -0
@@ -0,0 +1,297 @@
1
+ <template>
2
+ <view v-if="visible" class="mu-picker" :class="[panelShow && 'mu-picker--open']">
3
+ <!-- 遮罩层 -->
4
+ <view class="mu-picker__mask" @tap="handleClose"></view>
5
+
6
+ <!-- 底部面板 Panel -->
7
+ <view class="mu-picker__panel" :class="[panelShow && 'mu-picker__panel--show']" @tap.stop>
8
+ <!-- 顶部工具栏 Toolbar -->
9
+ <view class="mu-picker__toolbar">
10
+ <view class="mu-picker__btn mu-picker__btn--cancel mu-touchable-flat" @tap="handleClose">
11
+ <text class="mu-picker__btn-text">取消</text>
12
+ </view>
13
+ <text class="mu-picker__title">{{ title }}</text>
14
+ <view class="mu-picker__btn mu-picker__btn--confirm mu-touchable-flat" @tap="handleConfirm">
15
+ <text class="mu-picker__btn-text mu-picker__btn-text--confirm">确定</text>
16
+ </view>
17
+ </view>
18
+
19
+ <!-- 选单 View 区域 -->
20
+ <view class="mu-picker__body">
21
+ <picker-view
22
+ :value="pickerValue"
23
+ class="mu-picker__view"
24
+ indicator-style="height: 88rpx; border-top: 1rpx solid rgba(226, 232, 240, 0.8); border-bottom: 1rpx solid rgba(226, 232, 240, 0.8);"
25
+ @change="onPickerChange"
26
+ >
27
+ <picker-view-column v-for="(col, ci) in formattedColumns" :key="ci">
28
+ <view v-for="(item, ii) in col" :key="ii" class="mu-picker__col-item">
29
+ <text class="mu-picker__col-text" :class="{ 'mu-picker__col-text--active': pickerValue[ci] === ii }">
30
+ {{ getItemLabel(item) }}
31
+ </text>
32
+ </view>
33
+ </picker-view-column>
34
+ </picker-view>
35
+ </view>
36
+ </view>
37
+ </view>
38
+ </template>
39
+
40
+ <script setup>
41
+ import { ref, computed, watch } from 'vue'
42
+
43
+ const props = defineProps({
44
+ show: { type: Boolean, default: false },
45
+ modelValue: { type: Array, default: () => [] },
46
+ value: { type: Array, default: () => [] }, // 兼容旧属性
47
+ columns: { type: Array, default: () => [] },
48
+ title: { type: String, default: '请选择' },
49
+ labelKey: { type: String, default: 'label' },
50
+ valueKey: { type: String, default: 'value' },
51
+ childrenKey: { type: String, default: 'children' },
52
+ mode: { type: String, default: 'auto' } // auto | single | multi | cascade
53
+ })
54
+
55
+ const emit = defineEmits(['confirm', 'change', 'close', 'cancel', 'update:show', 'update:modelValue', 'update:value'])
56
+
57
+ const visible = ref(false)
58
+ const panelShow = ref(false)
59
+ const pickerValue = ref([])
60
+
61
+ function getItemLabel(item) {
62
+ if (typeof item === 'object' && item !== null) {
63
+ return (item[props.labelKey] !== undefined ? item[props.labelKey] : (item.label !== undefined ? item.label : String(item)))
64
+ }
65
+ return String(item)
66
+ }
67
+
68
+ function getItemValue(item) {
69
+ if (typeof item === 'object' && item !== null) {
70
+ return (item[props.valueKey] !== undefined ? item[props.valueKey] : (item.value !== undefined ? item.value : item))
71
+ }
72
+ return item
73
+ }
74
+
75
+ // 格式化后的多列列数据
76
+ const formattedColumns = computed(() => {
77
+ if (!props.columns || props.columns.length === 0) return []
78
+
79
+ // 1. 独立单列 / 简单一维数组 ['男', '女']
80
+ if (!Array.isArray(props.columns[0])) {
81
+ // 判断是否为级联数据 (包含 childrenKey)
82
+ if (props.columns[0] && typeof props.columns[0] === 'object' && props.columns[0][props.childrenKey]) {
83
+ // 级联模式 (Cascade)
84
+ const cols = []
85
+ let list = props.columns
86
+ let depth = 0
87
+ while (list && list.length && depth < 4) {
88
+ cols.push(list)
89
+ const selectedIdx = pickerValue.value[depth] || 0
90
+ const currentItem = list[selectedIdx] || list[0]
91
+ if (currentItem && currentItem[props.childrenKey]) {
92
+ list = currentItem[props.childrenKey]
93
+ } else {
94
+ break
95
+ }
96
+ depth++
97
+ }
98
+ return cols
99
+ }
100
+ // 普通单列
101
+ return [props.columns]
102
+ }
103
+
104
+ // 2. 多列二维数组 [['周一', '周二'], ['上午', '下午']]
105
+ return props.columns
106
+ })
107
+
108
+ function onPickerChange(e) {
109
+ const vals = e.detail.value || []
110
+ pickerValue.value = vals
111
+
112
+ // 安全防越界校准
113
+ const selectedItems = []
114
+ const selectedValues = []
115
+
116
+ for (let colIdx = 0; colIdx < formattedColumns.value.length; colIdx++) {
117
+ const col = formattedColumns.value[colIdx] || []
118
+ let idx = vals[colIdx] || 0
119
+ if (idx >= col.length) {
120
+ idx = 0
121
+ pickerValue.value[colIdx] = 0
122
+ }
123
+ const item = col[idx]
124
+ if (item != null) {
125
+ selectedItems.push(item)
126
+ selectedValues.push(getItemValue(item))
127
+ }
128
+ }
129
+
130
+ emit('change', { indexs: [...pickerValue.value], items: selectedItems, values: selectedValues })
131
+ }
132
+
133
+ function getSelectedResult() {
134
+ const items = pickerValue.value.map((idx, colIdx) => (formattedColumns.value[colIdx] && formattedColumns.value[colIdx][idx]) || (formattedColumns.value[colIdx] && formattedColumns.value[colIdx][0]))
135
+ const values = items.map(item => item != null ? getItemValue(item) : '')
136
+ return { indexs: [...pickerValue.value], items, values }
137
+ }
138
+
139
+ function handleConfirm() {
140
+ const result = getSelectedResult()
141
+ emit('confirm', result)
142
+ emit('update:modelValue', result.values)
143
+ emit('update:value', result.values)
144
+ handleClose()
145
+ }
146
+
147
+ function handleClose() {
148
+ panelShow.value = false
149
+ emit('update:show', false)
150
+ emit('cancel')
151
+ setTimeout(() => {
152
+ visible.value = false
153
+ emit('close')
154
+ }, 250)
155
+ }
156
+
157
+ watch(() => props.show, (val) => {
158
+ if (val) {
159
+ visible.value = true
160
+ const initVal = props.modelValue.length ? props.modelValue : props.value
161
+ pickerValue.value = initVal.length ? [...initVal] : [0, 0, 0]
162
+ setTimeout(() => {
163
+ panelShow.value = true
164
+ }, 30)
165
+ } else {
166
+ panelShow.value = false
167
+ setTimeout(() => {
168
+ visible.value = false
169
+ }, 250)
170
+ }
171
+ }, { immediate: true })
172
+ </script>
173
+
174
+ <style lang="scss" scoped>
175
+ @import "@/uni.scss";
176
+
177
+ .mu-picker {
178
+ position: fixed;
179
+ inset: 0;
180
+ z-index: $mu-z-popup;
181
+ display: flex;
182
+ flex-direction: column;
183
+ justify-content: flex-end;
184
+ box-sizing: border-box;
185
+
186
+ &__mask {
187
+ position: absolute;
188
+ inset: 0;
189
+ background: rgba(15, 23, 42, 0.45);
190
+ backdrop-filter: none !important;
191
+ opacity: 0;
192
+ transition: opacity 0.25s ease;
193
+ }
194
+
195
+ &--open &__mask {
196
+ opacity: 1;
197
+ }
198
+
199
+ &__panel {
200
+ position: relative;
201
+ background: #ffffff;
202
+ border-radius: 32rpx 32rpx 0 0;
203
+ transform: translateY(100%);
204
+ transition: transform 0.3s cubic-bezier(0.25, 1, 0.5, 1);
205
+ z-index: 2;
206
+ overflow: hidden;
207
+
208
+ &--show {
209
+ transform: translateY(0);
210
+ }
211
+ }
212
+
213
+ &__toolbar {
214
+ display: flex;
215
+ align-items: center;
216
+ justify-content: space-between;
217
+ padding: 28rpx 32rpx;
218
+ border-bottom: 1rpx solid rgba(226, 232, 240, 0.8);
219
+ }
220
+
221
+ &__btn {
222
+ padding: 8rpx 16rpx;
223
+
224
+ &-text {
225
+ font-size: 28rpx;
226
+ color: #64748B;
227
+ font-weight: 600;
228
+
229
+ &--confirm {
230
+ color: #171717;
231
+ font-weight: 700;
232
+ }
233
+ }
234
+ }
235
+
236
+ &__title {
237
+ font-size: 30rpx;
238
+ color: $mu-text-primary;
239
+ font-weight: 800;
240
+ letter-spacing: -0.5rpx;
241
+ }
242
+
243
+ &__body {
244
+ height: 480rpx;
245
+ padding: 0 16rpx;
246
+ }
247
+
248
+ &__view {
249
+ width: 100%;
250
+ height: 100%;
251
+ }
252
+
253
+ &__col-item {
254
+ display: flex;
255
+ align-items: center;
256
+ justify-content: center;
257
+ height: 88rpx;
258
+ }
259
+
260
+ &__col-text {
261
+ font-size: 30rpx;
262
+ color: #94A3B8;
263
+ font-weight: 500;
264
+ transition: all 0.2s ease;
265
+
266
+ &--active {
267
+ color: $mu-text-primary;
268
+ font-weight: 700;
269
+ font-size: 32rpx;
270
+ }
271
+ }
272
+ }
273
+
274
+ .mu-dark, page.mu-dark {
275
+
276
+ .mu-picker {
277
+ &__mask { background: rgba(0, 0, 0, 0.65); }
278
+ &__panel { background: #14141E !important; }
279
+ &__toolbar { border-color: rgba(255, 255, 255, 0.08); }
280
+ &__title { color: $mu-dark-text-primary; }
281
+ &__btn-text { color: $mu-dark-text-secondary; &--confirm { color: #FFFFFF; } }
282
+ &__col-text { color: rgba(255, 255, 255, 0.4); &--active { color: $mu-dark-text-primary; } }
283
+ }
284
+ }
285
+
286
+ @media (prefers-color-scheme: dark) {
287
+
288
+ .mu-picker {
289
+ &__mask { background: rgba(0, 0, 0, 0.65); }
290
+ &__panel { background: #14141E !important; }
291
+ &__toolbar { border-color: rgba(255, 255, 255, 0.08); }
292
+ &__title { color: $mu-dark-text-primary; }
293
+ &__btn-text { color: $mu-dark-text-secondary; &--confirm { color: #FFFFFF; } }
294
+ &__col-text { color: rgba(255, 255, 255, 0.4); &--active { color: $mu-dark-text-primary; } }
295
+ }
296
+ }
297
+ </style>
@@ -0,0 +1,297 @@
1
+ <template>
2
+ <view v-if="visible" class="mu-popup" :class="[`mu-popup--${position}`]">
3
+ <!-- 背景遮罩层 -->
4
+ <view
5
+ v-if="mask"
6
+ class="mu-popup__mask"
7
+ :class="[animating && 'mu-popup__mask--show']"
8
+ :style="maskStyle"
9
+ @tap="handleMaskClick"
10
+ ></view>
11
+
12
+ <!-- 弹窗主体内容 Panel -->
13
+ <view
14
+ class="mu-popup__content"
15
+ :class="[
16
+ contentClass,
17
+ transparent && 'mu-popup__content--transparent'
18
+ ]"
19
+ :style="contentStyle"
20
+ @tap.stop
21
+ >
22
+ <!-- 内置右上角/左上角/正下方关闭按钮 -->
23
+ <view
24
+ v-if="closable"
25
+ class="mu-popup__close"
26
+ :class="[`mu-popup__close--${closePosition}`]"
27
+ @tap="handleClose"
28
+ >
29
+ <mu-icon name="close" :size="closeIconSize" :color="closeIconColor" />
30
+ </view>
31
+
32
+ <!-- 弹窗卡片内容插槽 -->
33
+ <slot></slot>
34
+ </view>
35
+ </view>
36
+ </template>
37
+
38
+ <script setup>
39
+ import { ref, computed, watch } from 'vue'
40
+
41
+ const props = defineProps({
42
+ show: { type: Boolean, default: false },
43
+ position: { type: String, default: 'center' }, // top | center | bottom | left | right
44
+ mask: { type: Boolean, default: true }, // 是否显示背景遮罩
45
+ maskClosable: { type: Boolean, default: true }, // 点击遮罩是否关闭
46
+ maskColor: { type: String, default: '' },
47
+ closable: { type: Boolean, default: false }, // 是否显示关闭按键
48
+ closePosition: { type: String, default: 'top-right' }, // top-right | top-left | bottom (活动海报弹窗下方圈圈按键)
49
+ transparent: { type: Boolean, default: false }, // 是否透明背景(无背景/无阴影,专用于图片/活动卡片)
50
+ background: { type: String, default: '' },
51
+ round: { type: Boolean, default: false },
52
+ width: { type: String, default: '' },
53
+ height: { type: String, default: '' },
54
+ zIndex: { type: [Number, String], default: 1000 },
55
+ duration: { type: Number, default: 300 }
56
+ })
57
+
58
+ const emit = defineEmits(['close', 'open', 'update:show'])
59
+
60
+ const visible = ref(false)
61
+ const animating = ref(false)
62
+
63
+ const contentClass = computed(() => ({
64
+ 'mu-popup__content--show': animating.value,
65
+ 'mu-popup__content--round': props.round
66
+ }))
67
+
68
+ const closeIconColor = computed(() => {
69
+ if (props.closePosition === 'bottom') return '#FFFFFF'
70
+ return props.transparent ? '#FFFFFF' : '#64748B'
71
+ })
72
+
73
+ const closeIconSize = computed(() => {
74
+ if (props.closePosition === 'bottom') return 20
75
+ return 16
76
+ })
77
+
78
+ const maskStyle = computed(() => {
79
+ if (props.maskColor) return { background: props.maskColor }
80
+ return {}
81
+ })
82
+
83
+ const contentStyle = computed(() => {
84
+ const style = { zIndex: props.zIndex }
85
+ if (props.width) style.width = props.width
86
+ if (props.height) style.height = props.height
87
+
88
+ if (props.transparent) {
89
+ style.background = 'transparent'
90
+ style.boxShadow = 'none'
91
+ style.border = 'none'
92
+ } else if (props.background) {
93
+ style.background = props.background
94
+ }
95
+
96
+ return style
97
+ })
98
+
99
+ function handleMaskClick() {
100
+ if (props.maskClosable) handleClose()
101
+ }
102
+
103
+ function handleClose() {
104
+ animating.value = false
105
+ emit('update:show', false)
106
+ setTimeout(() => {
107
+ visible.value = false
108
+ emit('close')
109
+ }, props.duration)
110
+ }
111
+
112
+ watch(() => props.show, (val) => {
113
+ if (val) {
114
+ visible.value = true
115
+ setTimeout(() => {
116
+ animating.value = true
117
+ emit('open')
118
+ }, 30)
119
+ } else {
120
+ animating.value = false
121
+ setTimeout(() => {
122
+ visible.value = false
123
+ emit('close')
124
+ }, props.duration)
125
+ }
126
+ }, { immediate: true })
127
+
128
+ defineExpose({ close: handleClose, open: () => { visible.value = true } })
129
+ </script>
130
+
131
+ <style lang="scss" scoped>
132
+ @import "@/uni.scss";
133
+
134
+ .mu-popup {
135
+ position: fixed;
136
+ left: 0;
137
+ right: 0;
138
+ top: 0;
139
+ bottom: 0;
140
+ z-index: $mu-z-popup;
141
+ display: flex;
142
+ pointer-events: none;
143
+
144
+ &--bottom { align-items: flex-end; justify-content: center; }
145
+ &--top { align-items: flex-start; justify-content: center; }
146
+ &--left { align-items: stretch; justify-content: flex-start; }
147
+ &--right { align-items: stretch; justify-content: flex-end; }
148
+ &--center { align-items: center; justify-content: center; }
149
+
150
+ &__mask {
151
+ position: absolute;
152
+ left: 0;
153
+ right: 0;
154
+ top: 0;
155
+ bottom: 0;
156
+ background: rgba(15, 23, 42, 0.55);
157
+ backdrop-filter: blur(12px);
158
+ opacity: 0;
159
+ transition: opacity 0.3s ease;
160
+ pointer-events: auto;
161
+
162
+ &--show {
163
+ opacity: 1;
164
+ }
165
+ }
166
+
167
+ &__content {
168
+ position: relative;
169
+ background: #ffffff;
170
+ pointer-events: auto;
171
+ transition: transform 0.35s cubic-bezier(0.25, 1, 0.5, 1), opacity 0.3s ease;
172
+ max-height: 100vh;
173
+ max-width: 100vw;
174
+ box-shadow: 0 24rpx 60rpx -12rpx rgba(15, 23, 42, 0.25);
175
+ box-sizing: border-box;
176
+
177
+ &--round {
178
+ border-radius: 36rpx;
179
+ }
180
+
181
+ &--transparent {
182
+ background: transparent !important;
183
+ box-shadow: none !important;
184
+ border: none !important;
185
+ }
186
+ }
187
+
188
+ &--bottom .mu-popup__content {
189
+ width: 100%;
190
+ transform: translateY(100%);
191
+ border-radius: 36rpx 36rpx 0 0;
192
+ &.mu-popup__content--show { transform: translateY(0); }
193
+ }
194
+
195
+ &--top .mu-popup__content {
196
+ width: 100%;
197
+ transform: translateY(-100%);
198
+ border-radius: 0 0 36rpx 36rpx;
199
+ &.mu-popup__content--show { transform: translateY(0); }
200
+ }
201
+
202
+ &--left .mu-popup__content {
203
+ height: 100%;
204
+ transform: translateX(-100%);
205
+ &.mu-popup__content--show { transform: translateX(0); }
206
+ }
207
+
208
+ &--right .mu-popup__content {
209
+ height: 100%;
210
+ transform: translateX(100%);
211
+ &.mu-popup__content--show { transform: translateX(0); }
212
+ }
213
+
214
+ &--center .mu-popup__content {
215
+ opacity: 0;
216
+ transform: scale(0.85);
217
+ border-radius: 36rpx;
218
+ &.mu-popup__content--show { opacity: 1; transform: scale(1); }
219
+ }
220
+
221
+ /* 关闭按钮定位 */
222
+ &__close {
223
+ position: absolute;
224
+ z-index: 20;
225
+ display: flex;
226
+ align-items: center;
227
+ justify-content: center;
228
+ cursor: pointer;
229
+ transition: transform 0.2s ease;
230
+
231
+ &:active {
232
+ transform: scale(0.88);
233
+ }
234
+
235
+ &--top-right {
236
+ top: 24rpx;
237
+ right: 24rpx;
238
+ width: 48rpx;
239
+ height: 48rpx;
240
+ border-radius: 50%;
241
+ background: rgba(148, 163, 184, 0.15);
242
+ }
243
+
244
+ &--top-left {
245
+ top: 24rpx;
246
+ left: 24rpx;
247
+ width: 48rpx;
248
+ height: 48rpx;
249
+ border-radius: 50%;
250
+ background: rgba(148, 163, 184, 0.15);
251
+ }
252
+
253
+ /* 活动海报弹窗专用的下方挂载圆形关闭按钮 */
254
+ &--bottom {
255
+ bottom: -100rpx;
256
+ left: 50%;
257
+ transform: translateX(-50%);
258
+ width: 72rpx;
259
+ height: 72rpx;
260
+ border-radius: 50%;
261
+ background: rgba(255, 255, 255, 0.2);
262
+ border: 2rpx solid rgba(255, 255, 255, 0.6);
263
+ backdrop-filter: blur(10px);
264
+
265
+ &:active {
266
+ transform: translateX(-50%) scale(0.88);
267
+ }
268
+ }
269
+ }
270
+ }
271
+
272
+ .mu-dark, page.mu-dark {
273
+
274
+ .mu-popup {
275
+ &__content {
276
+ background: $mu-dark-bg-base;
277
+ box-shadow: 0 32rpx 64rpx rgba(0, 0, 0, 0.6);
278
+ }
279
+ &__close--top-right, &__close--top-left {
280
+ background: rgba(255, 255, 255, 0.12);
281
+ }
282
+ }
283
+ }
284
+
285
+ @media (prefers-color-scheme: dark) {
286
+
287
+ .mu-popup {
288
+ &__content {
289
+ background: $mu-dark-bg-base;
290
+ box-shadow: 0 32rpx 64rpx rgba(0, 0, 0, 0.6);
291
+ }
292
+ &__close--top-right, &__close--top-left {
293
+ background: rgba(255, 255, 255, 0.12);
294
+ }
295
+ }
296
+ }
297
+ </style>