uview-plus 3.5.17 → 3.5.22
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.
- package/changelog.md +15 -0
- package/components/u-checkbox/u-checkbox.vue +3 -2
- package/components/u-coupon/u-coupon.vue +406 -0
- package/components/u-goods-sku/u-goods-sku.vue +432 -0
- package/components/u-popup/popup.js +5 -2
- package/components/u-popup/props.js +15 -0
- package/components/u-popup/u-popup.vue +120 -5
- package/package.json +1 -1
package/changelog.md
CHANGED
|
@@ -1,3 +1,18 @@
|
|
|
1
|
+
## 3.5.22(2025-08-28)
|
|
2
|
+
feat: 新增goods-sku商品SKU选购组件
|
|
3
|
+
|
|
4
|
+
## 3.5.21(2025-08-27)
|
|
5
|
+
fix: 修复popup组件手势控制参数注释
|
|
6
|
+
|
|
7
|
+
## 3.5.20(2025-08-27)
|
|
8
|
+
improvement: 提升checkbox条件编译兼容性
|
|
9
|
+
|
|
10
|
+
## 3.5.19(2025-08-27)
|
|
11
|
+
feat: popup新增iOS风格手势控制上下高度及下滑关闭
|
|
12
|
+
|
|
13
|
+
## 3.5.18(2025-08-26)
|
|
14
|
+
feat: 新增coupon优惠券组件
|
|
15
|
+
|
|
1
16
|
## 3.5.17(2025-08-26)
|
|
2
17
|
fix: 分支合并冲突修复
|
|
3
18
|
|
|
@@ -199,11 +199,12 @@
|
|
|
199
199
|
if (!this.parent) {
|
|
200
200
|
error('up-checkbox必须搭配up-checkbox-group组件使用')
|
|
201
201
|
}
|
|
202
|
+
let value = '';
|
|
202
203
|
// #ifdef VUE2
|
|
203
|
-
|
|
204
|
+
value = this.parentData.value
|
|
204
205
|
// #endif
|
|
205
206
|
// #ifdef VUE3
|
|
206
|
-
|
|
207
|
+
value = this.parentData.modelValue
|
|
207
208
|
// #endif
|
|
208
209
|
// 设置初始化时,是否默认选中的状态,父组件u-checkbox-group的value可能是array,所以额外判断
|
|
209
210
|
if (this.checked) {
|
|
@@ -0,0 +1,406 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<view class="up-coupon" :class="[`up-coupon--${shape}`, `up-coupon--${type}`, `up-coupon--${size}`, {'up-coupon--disabled': disabled}]"
|
|
3
|
+
:style="[couponStyle]" @click="handleClick">
|
|
4
|
+
<view class="up-coupon__content">
|
|
5
|
+
<!-- 左侧金额区域 -->
|
|
6
|
+
<view class="up-coupon__amount">
|
|
7
|
+
<slot name="unit" :unit="unit" :unitPosition="unitPosition" v-if="unitPosition === 'left'">
|
|
8
|
+
<text class="up-coupon__amount-unit" v-if="unitPosition === 'left'">{{ unit }}</text>
|
|
9
|
+
</slot>
|
|
10
|
+
<slot name="amount" :amount="amount">
|
|
11
|
+
<text class="up-coupon__amount-value">{{ amount }}</text>
|
|
12
|
+
</slot>
|
|
13
|
+
<slot name="unit" :unit="unit" :unitPosition="unitPosition" v-if="unitPosition === 'right'">
|
|
14
|
+
<text class="up-coupon__amount-unit" v-if="unitPosition === 'right'">{{ unit }}</text>
|
|
15
|
+
</slot>
|
|
16
|
+
<slot name="limit" :limit="limit">
|
|
17
|
+
<text class="up-coupon__amount-limit" v-if="limit">{{ limit }}</text>
|
|
18
|
+
</slot>
|
|
19
|
+
</view>
|
|
20
|
+
|
|
21
|
+
<!-- 中间描述区域 -->
|
|
22
|
+
<view class="up-coupon__info">
|
|
23
|
+
<slot name="title" :title="title">
|
|
24
|
+
<text class="up-coupon__info-title">{{ title }}</text>
|
|
25
|
+
</slot>
|
|
26
|
+
<slot name="desc" :desc="desc">
|
|
27
|
+
<text class="up-coupon__info-desc" v-if="desc">{{ desc }}</text>
|
|
28
|
+
</slot>
|
|
29
|
+
<slot name="time" :time="time">
|
|
30
|
+
<text class="up-coupon__info-time" v-if="time">{{ time }}</text>
|
|
31
|
+
</slot>
|
|
32
|
+
</view>
|
|
33
|
+
|
|
34
|
+
<!-- 右侧操作区域 -->
|
|
35
|
+
<view class="up-coupon__action u-padding-right-20">
|
|
36
|
+
<slot name="action" :actionText="actionText" :circle="circle">
|
|
37
|
+
<up-tag type="error" :bgColor="type ? 'transparent' : '#eb433d'"
|
|
38
|
+
:borderColor="type ? '#eee' : '#eb433d'" borderRadius="6px"
|
|
39
|
+
size="medium" class="up-coupon__action-text"
|
|
40
|
+
:shape="circle ? 'circle': 'circle'">{{ actionText }}</up-tag>
|
|
41
|
+
</slot>
|
|
42
|
+
</view>
|
|
43
|
+
</view>
|
|
44
|
+
|
|
45
|
+
<!-- 红包绳子效果 -->
|
|
46
|
+
<view v-if="shape === 'envelope'" class="up-coupon__rope"></view>
|
|
47
|
+
|
|
48
|
+
<!-- 默认插槽,可用于添加额外内容 -->
|
|
49
|
+
<slot></slot>
|
|
50
|
+
</view>
|
|
51
|
+
</template>
|
|
52
|
+
|
|
53
|
+
<script>
|
|
54
|
+
export default {
|
|
55
|
+
name: 'up-coupon',
|
|
56
|
+
props: {
|
|
57
|
+
// 金额
|
|
58
|
+
amount: {
|
|
59
|
+
type: [String, Number],
|
|
60
|
+
default: ''
|
|
61
|
+
},
|
|
62
|
+
// 金额单位
|
|
63
|
+
unit: {
|
|
64
|
+
type: String,
|
|
65
|
+
default: '¥'
|
|
66
|
+
},
|
|
67
|
+
// 单位位置
|
|
68
|
+
unitPosition: {
|
|
69
|
+
type: String,
|
|
70
|
+
default: 'left'
|
|
71
|
+
},
|
|
72
|
+
// 使用限制
|
|
73
|
+
limit: {
|
|
74
|
+
type: String,
|
|
75
|
+
default: ''
|
|
76
|
+
},
|
|
77
|
+
// 标题
|
|
78
|
+
title: {
|
|
79
|
+
type: String,
|
|
80
|
+
default: '优惠券'
|
|
81
|
+
},
|
|
82
|
+
// 描述
|
|
83
|
+
desc: {
|
|
84
|
+
type: String,
|
|
85
|
+
default: ''
|
|
86
|
+
},
|
|
87
|
+
// 有效期
|
|
88
|
+
time: {
|
|
89
|
+
type: String,
|
|
90
|
+
default: ''
|
|
91
|
+
},
|
|
92
|
+
// 操作按钮文字
|
|
93
|
+
actionText: {
|
|
94
|
+
type: String,
|
|
95
|
+
default: '使用'
|
|
96
|
+
},
|
|
97
|
+
// 形状:coupon-优惠券, envelope-红包, card-卡片
|
|
98
|
+
shape: {
|
|
99
|
+
type: String,
|
|
100
|
+
default: 'coupon'
|
|
101
|
+
},
|
|
102
|
+
// 尺寸:small, medium, large
|
|
103
|
+
size: {
|
|
104
|
+
type: String,
|
|
105
|
+
default: 'medium'
|
|
106
|
+
},
|
|
107
|
+
// 是否圆形按钮
|
|
108
|
+
circle: {
|
|
109
|
+
type: Boolean,
|
|
110
|
+
default: false
|
|
111
|
+
},
|
|
112
|
+
// 是否禁用
|
|
113
|
+
disabled: {
|
|
114
|
+
type: Boolean,
|
|
115
|
+
default: false
|
|
116
|
+
},
|
|
117
|
+
// 背景颜色
|
|
118
|
+
bgColor: {
|
|
119
|
+
type: String,
|
|
120
|
+
default: ''
|
|
121
|
+
},
|
|
122
|
+
// 文字颜色
|
|
123
|
+
color: {
|
|
124
|
+
type: String,
|
|
125
|
+
default: ''
|
|
126
|
+
},
|
|
127
|
+
// 内置背景类型
|
|
128
|
+
type: {
|
|
129
|
+
type: String,
|
|
130
|
+
default: ''
|
|
131
|
+
},
|
|
132
|
+
},
|
|
133
|
+
computed: {
|
|
134
|
+
couponStyle() {
|
|
135
|
+
const style = {};
|
|
136
|
+
if (this.bgColor) style.background = this.bgColor;
|
|
137
|
+
if (this.color) style.color = this.color;
|
|
138
|
+
return style;
|
|
139
|
+
},
|
|
140
|
+
dotCount() {
|
|
141
|
+
// 根据尺寸计算锯齿数量
|
|
142
|
+
const map = {
|
|
143
|
+
small: 8,
|
|
144
|
+
medium: 10,
|
|
145
|
+
large: 12
|
|
146
|
+
};
|
|
147
|
+
return map[this.size] || 10;
|
|
148
|
+
}
|
|
149
|
+
},
|
|
150
|
+
methods: {
|
|
151
|
+
handleClick() {
|
|
152
|
+
if (this.disabled) return;
|
|
153
|
+
this.$emit('click');
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
</script>
|
|
158
|
+
|
|
159
|
+
<style lang="scss" scoped>
|
|
160
|
+
.up-coupon {
|
|
161
|
+
position: relative;
|
|
162
|
+
overflow: hidden;
|
|
163
|
+
border-radius: 8rpx;
|
|
164
|
+
background: #ffebf0;
|
|
165
|
+
color: $u-main-color;
|
|
166
|
+
|
|
167
|
+
&--coupon {
|
|
168
|
+
border-radius: 16rpx;
|
|
169
|
+
overflow: hidden;
|
|
170
|
+
|
|
171
|
+
&::before {
|
|
172
|
+
content: '';
|
|
173
|
+
position: absolute;
|
|
174
|
+
left: -24rpx;
|
|
175
|
+
top: 50%;
|
|
176
|
+
transform: translateY(-50%);
|
|
177
|
+
width: 48rpx;
|
|
178
|
+
height: 48rpx;
|
|
179
|
+
background-color: #fff;
|
|
180
|
+
border-radius: 50%;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
&::after {
|
|
184
|
+
content: '';
|
|
185
|
+
position: absolute;
|
|
186
|
+
right: -24rpx;
|
|
187
|
+
top: 50%;
|
|
188
|
+
transform: translateY(-50%);
|
|
189
|
+
width: 48rpx;
|
|
190
|
+
height: 48rpx;
|
|
191
|
+
background-color: #fff;
|
|
192
|
+
border-radius: 50%;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
&--envelope {
|
|
197
|
+
border-radius: 16rpx;
|
|
198
|
+
|
|
199
|
+
&::before {
|
|
200
|
+
content: '';
|
|
201
|
+
position: absolute;
|
|
202
|
+
left: 0;
|
|
203
|
+
top: 0;
|
|
204
|
+
right: 0;
|
|
205
|
+
height: 20rpx;
|
|
206
|
+
background: repeating-linear-gradient(-45deg, #ffd000, #ffd000 10rpx, #ffa000 10rpx, #ffa000 20rpx);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
&--card {
|
|
211
|
+
border-radius: 16rpx;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
width: 100%;
|
|
215
|
+
|
|
216
|
+
&--small {
|
|
217
|
+
// width: 520rpx;
|
|
218
|
+
height: 160rpx;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
&--medium {
|
|
222
|
+
// width: 600rpx;
|
|
223
|
+
height: 180rpx;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
&--large {
|
|
227
|
+
// width: 700rpx;
|
|
228
|
+
height: 220rpx;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
&--disabled {
|
|
232
|
+
opacity: 0.5;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
&__content {
|
|
236
|
+
display: flex;
|
|
237
|
+
flex-direction: row;
|
|
238
|
+
align-items: center;
|
|
239
|
+
justify-content: space-between;
|
|
240
|
+
height: 100%;
|
|
241
|
+
padding: 0 30rpx;
|
|
242
|
+
position: relative;
|
|
243
|
+
z-index: 2;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
&__amount {
|
|
247
|
+
display: flex;
|
|
248
|
+
flex-direction: column;
|
|
249
|
+
align-items: flex-start;
|
|
250
|
+
padding-left: 10rpx;
|
|
251
|
+
padding-right: 30rpx;
|
|
252
|
+
border-right: 1px dashed #ccc;
|
|
253
|
+
|
|
254
|
+
&-unit {
|
|
255
|
+
font-size: 24rpx;
|
|
256
|
+
font-weight: normal;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
&-value {
|
|
260
|
+
font-size: 56rpx;
|
|
261
|
+
font-weight: bold;
|
|
262
|
+
color: red;
|
|
263
|
+
line-height: 1;
|
|
264
|
+
margin: 10rpx 0;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
&-limit {
|
|
268
|
+
font-size: 24rpx;
|
|
269
|
+
opacity: 0.9;
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
&__info {
|
|
274
|
+
flex: 1;
|
|
275
|
+
display: flex;
|
|
276
|
+
flex-direction: column;
|
|
277
|
+
align-items: flex-start;
|
|
278
|
+
padding-left: 30rpx;
|
|
279
|
+
|
|
280
|
+
&-title {
|
|
281
|
+
font-size: 32rpx;
|
|
282
|
+
font-weight: bold;
|
|
283
|
+
margin-bottom: 10rpx;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
&-desc {
|
|
287
|
+
font-size: 24rpx;
|
|
288
|
+
opacity: 0.9;
|
|
289
|
+
margin-bottom: 10rpx;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
&-time {
|
|
293
|
+
font-size: 20rpx;
|
|
294
|
+
opacity: 0.8;
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
&__action {
|
|
299
|
+
display: flex;
|
|
300
|
+
flex-direction: row;
|
|
301
|
+
align-items: center;
|
|
302
|
+
justify-content: center;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
&__dots {
|
|
306
|
+
position: absolute;
|
|
307
|
+
left: 0;
|
|
308
|
+
top: 0;
|
|
309
|
+
bottom: 0;
|
|
310
|
+
width: 100%;
|
|
311
|
+
display: flex;
|
|
312
|
+
flex-direction: column;
|
|
313
|
+
justify-content: space-between;
|
|
314
|
+
padding: 30rpx 0;
|
|
315
|
+
z-index: 1;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
&__dot {
|
|
319
|
+
width: 32rpx;
|
|
320
|
+
height: 32rpx;
|
|
321
|
+
background-color: #fff;
|
|
322
|
+
border-radius: 50%;
|
|
323
|
+
margin: 0 -16rpx;
|
|
324
|
+
z-index: 3;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
&__rope {
|
|
328
|
+
position: absolute;
|
|
329
|
+
top: -40rpx;
|
|
330
|
+
left: 50%;
|
|
331
|
+
transform: translateX(-50%);
|
|
332
|
+
width: 80rpx;
|
|
333
|
+
height: 80rpx;
|
|
334
|
+
background: linear-gradient(to right, #ffd000, #ffa000);
|
|
335
|
+
border-radius: 40rpx 40rpx 0 0;
|
|
336
|
+
z-index: 1;
|
|
337
|
+
|
|
338
|
+
&::before {
|
|
339
|
+
content: '';
|
|
340
|
+
position: absolute;
|
|
341
|
+
top: 0;
|
|
342
|
+
left: -20rpx;
|
|
343
|
+
width: 20rpx;
|
|
344
|
+
height: 40rpx;
|
|
345
|
+
background: linear-gradient(to bottom, #ffd000, #ffa000);
|
|
346
|
+
border-radius: 10rpx 0 0 10rpx;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
&::after {
|
|
350
|
+
content: '';
|
|
351
|
+
position: absolute;
|
|
352
|
+
top: 0;
|
|
353
|
+
right: -20rpx;
|
|
354
|
+
width: 20rpx;
|
|
355
|
+
height: 40rpx;
|
|
356
|
+
background: linear-gradient(to bottom, #ffd000, #ffa000);
|
|
357
|
+
border-radius: 0 10rpx 10rpx 0;
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
// 不同主题样式
|
|
362
|
+
&--primary {
|
|
363
|
+
background: linear-gradient(90deg, #43afff, #3b8cff);
|
|
364
|
+
color: #fff;
|
|
365
|
+
.up-coupon__amount {
|
|
366
|
+
border-right: 1px dashed #eee;
|
|
367
|
+
}
|
|
368
|
+
.up-coupon__amount-value {
|
|
369
|
+
color: #fff;
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
&--success {
|
|
374
|
+
background: linear-gradient(90deg, #67dda9, #19be6b);
|
|
375
|
+
color: #fff !important;
|
|
376
|
+
.up-coupon__amount {
|
|
377
|
+
border-right: 1px dashed #eee;
|
|
378
|
+
}
|
|
379
|
+
.up-coupon__amount-value {
|
|
380
|
+
color: #fff;
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
&--warning {
|
|
385
|
+
background: linear-gradient(90deg, #ff9739, #ff6a39);
|
|
386
|
+
color: #fff;
|
|
387
|
+
.up-coupon__amount {
|
|
388
|
+
border-right: 1px dashed #eee;
|
|
389
|
+
}
|
|
390
|
+
.up-coupon__amount-value {
|
|
391
|
+
color: #fff;
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
&--error {
|
|
396
|
+
background: linear-gradient(90deg, #ff7070, #ff4747);
|
|
397
|
+
color: #fff;
|
|
398
|
+
.up-coupon__amount {
|
|
399
|
+
border-right: 1px dashed #eee;
|
|
400
|
+
}
|
|
401
|
+
.up-coupon__amount-value {
|
|
402
|
+
color: #fff;
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
</style>
|
|
@@ -0,0 +1,432 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<view class="up-goods-sku">
|
|
3
|
+
<view @click="open">
|
|
4
|
+
<slot name="trigger"></slot>
|
|
5
|
+
</view>
|
|
6
|
+
<up-popup
|
|
7
|
+
v-model:show="show"
|
|
8
|
+
mode="bottom"
|
|
9
|
+
:closeable="pageInline ? false : closeable"
|
|
10
|
+
:pageInline="pageInline"
|
|
11
|
+
:border-radius="20"
|
|
12
|
+
@close="close"
|
|
13
|
+
>
|
|
14
|
+
<view class="up-goods-sku-container" :style="{padding: pageInline ? '0px' : ''}">
|
|
15
|
+
<view class="up-goods-sku__header">
|
|
16
|
+
<slot name="header">
|
|
17
|
+
<view class="up-goods-sku__header__image">
|
|
18
|
+
<image :src="goodsInfo.image || goodsInfo.picture" mode="aspectFill"></image>
|
|
19
|
+
</view>
|
|
20
|
+
<view class="up-goods-sku__header__info">
|
|
21
|
+
<view class="up-goods-sku__header__info__price">
|
|
22
|
+
<text class="up-goods-sku__header__info__price__symbol">¥</text>
|
|
23
|
+
<text class="up-goods-sku__header__info__price__value">{{ price }}</text>
|
|
24
|
+
</view>
|
|
25
|
+
<view class="up-goods-sku__header__info__stock">库存 {{ stock }} 件</view>
|
|
26
|
+
<view class="up-goods-sku__header__info__selected">已选: {{ selectedSkuText }}</view>
|
|
27
|
+
</view>
|
|
28
|
+
</slot>
|
|
29
|
+
</view>
|
|
30
|
+
|
|
31
|
+
<scroll-view class="up-goods-sku__content" scroll-y>
|
|
32
|
+
<view v-for="(treeItem, index) in skuTree" :key="index" class="up-goods-sku__content__item">
|
|
33
|
+
<view class="up-goods-sku__content__item__title">{{ treeItem.label }}</view>
|
|
34
|
+
<view class="up-goods-sku__content__item__list">
|
|
35
|
+
<view
|
|
36
|
+
v-for="(leafItem, leafIndex) in treeItem.children"
|
|
37
|
+
:key="leafIndex"
|
|
38
|
+
class="up-goods-sku__content__item__list__item"
|
|
39
|
+
:class="{
|
|
40
|
+
'up-goods-sku__content__item__list__item--active': isSelected(treeItem.name, leafItem.id),
|
|
41
|
+
'up-goods-sku__content__item__list__item--disabled': isDisabled(treeItem.name, leafItem.id)
|
|
42
|
+
}"
|
|
43
|
+
@click="onSkuClick(treeItem.name, leafItem)"
|
|
44
|
+
>
|
|
45
|
+
<text>{{ leafItem.name }}</text>
|
|
46
|
+
</view>
|
|
47
|
+
</view>
|
|
48
|
+
</view>
|
|
49
|
+
|
|
50
|
+
<view class="up-goods-sku__content__count">
|
|
51
|
+
<view class="up-goods-sku__content__count__title">购买数量</view>
|
|
52
|
+
<view class="up-goods-sku__content__count__control">
|
|
53
|
+
<up-number-box
|
|
54
|
+
v-model="buyNum"
|
|
55
|
+
:min="1"
|
|
56
|
+
:max="maxBuyNum"
|
|
57
|
+
:disabled="!canBuy"
|
|
58
|
+
@change="onNumChange"
|
|
59
|
+
></up-number-box>
|
|
60
|
+
</view>
|
|
61
|
+
</view>
|
|
62
|
+
</scroll-view>
|
|
63
|
+
|
|
64
|
+
<view class="up-goods-sku__footer">
|
|
65
|
+
<up-button
|
|
66
|
+
type="primary"
|
|
67
|
+
:disabled="!canBuy"
|
|
68
|
+
@click="onConfirm"
|
|
69
|
+
>
|
|
70
|
+
{{ confirmText }}
|
|
71
|
+
</up-button>
|
|
72
|
+
</view>
|
|
73
|
+
</view>
|
|
74
|
+
</up-popup>
|
|
75
|
+
</view>
|
|
76
|
+
</template>
|
|
77
|
+
|
|
78
|
+
<script>
|
|
79
|
+
export default {
|
|
80
|
+
name: 'up-goods-sku',
|
|
81
|
+
props: {
|
|
82
|
+
// 商品信息
|
|
83
|
+
goodsInfo: {
|
|
84
|
+
type: Object,
|
|
85
|
+
default: () => ({})
|
|
86
|
+
},
|
|
87
|
+
// SKU树形结构
|
|
88
|
+
skuTree: {
|
|
89
|
+
type: Array,
|
|
90
|
+
default: () => []
|
|
91
|
+
},
|
|
92
|
+
// SKU列表
|
|
93
|
+
skuList: {
|
|
94
|
+
type: Array,
|
|
95
|
+
default: () => []
|
|
96
|
+
},
|
|
97
|
+
// 最大购买数量
|
|
98
|
+
maxBuy: {
|
|
99
|
+
type: Number,
|
|
100
|
+
default: 999
|
|
101
|
+
},
|
|
102
|
+
// 确认按钮文字
|
|
103
|
+
confirmText: {
|
|
104
|
+
type: String,
|
|
105
|
+
default: '确定'
|
|
106
|
+
},
|
|
107
|
+
// 是否显示关闭弹窗按钮
|
|
108
|
+
closeable: {
|
|
109
|
+
type: Boolean,
|
|
110
|
+
default: true
|
|
111
|
+
},
|
|
112
|
+
// 是否页面内联模式
|
|
113
|
+
pageInline: {
|
|
114
|
+
type: Boolean,
|
|
115
|
+
default: false
|
|
116
|
+
}
|
|
117
|
+
},
|
|
118
|
+
data() {
|
|
119
|
+
return {
|
|
120
|
+
show: false,
|
|
121
|
+
// 已选择的SKU
|
|
122
|
+
selectedSku: {},
|
|
123
|
+
// 购买数量
|
|
124
|
+
buyNum: 1
|
|
125
|
+
}
|
|
126
|
+
},
|
|
127
|
+
computed: {
|
|
128
|
+
// 当前价格
|
|
129
|
+
price() {
|
|
130
|
+
const selectedSkuComb = this.getSelectedSkuComb()
|
|
131
|
+
if (selectedSkuComb) {
|
|
132
|
+
return selectedSkuComb.price || selectedSkuComb.price_fee
|
|
133
|
+
}
|
|
134
|
+
return this.goodsInfo.price || this.goodsInfo.price_fee || 0
|
|
135
|
+
},
|
|
136
|
+
// 当前库存
|
|
137
|
+
stock() {
|
|
138
|
+
const selectedSkuComb = this.getSelectedSkuComb()
|
|
139
|
+
if (selectedSkuComb) {
|
|
140
|
+
return selectedSkuComb.stock || selectedSkuComb.quantity
|
|
141
|
+
}
|
|
142
|
+
return this.goodsInfo.stock || this.goodsInfo.quantity || 0
|
|
143
|
+
},
|
|
144
|
+
// 最大购买数量
|
|
145
|
+
maxBuyNum() {
|
|
146
|
+
const stock = this.stock
|
|
147
|
+
return stock > this.maxBuy ? this.maxBuy : stock
|
|
148
|
+
},
|
|
149
|
+
// 是否可以购买
|
|
150
|
+
canBuy() {
|
|
151
|
+
const selectedSkuCount = Object.keys(this.selectedSku).length
|
|
152
|
+
const skuTreeCount = this.skuTree.length
|
|
153
|
+
return selectedSkuCount === skuTreeCount && this.buyNum > 0 && this.stock > 0
|
|
154
|
+
},
|
|
155
|
+
// 已选SKU文字描述
|
|
156
|
+
selectedSkuText() {
|
|
157
|
+
const selected = []
|
|
158
|
+
Object.keys(this.selectedSku).forEach(key => {
|
|
159
|
+
const value = this.selectedSku[key]
|
|
160
|
+
if (value) {
|
|
161
|
+
this.skuTree.forEach(treeItem => {
|
|
162
|
+
if (treeItem.name === key) {
|
|
163
|
+
treeItem.children.forEach(leafItem => {
|
|
164
|
+
if (leafItem.id === value) {
|
|
165
|
+
selected.push(leafItem.name)
|
|
166
|
+
}
|
|
167
|
+
})
|
|
168
|
+
}
|
|
169
|
+
})
|
|
170
|
+
}
|
|
171
|
+
})
|
|
172
|
+
return selected.join(', ')
|
|
173
|
+
}
|
|
174
|
+
},
|
|
175
|
+
watch: {
|
|
176
|
+
},
|
|
177
|
+
emits: ['open', 'confirm', 'close'],
|
|
178
|
+
created() {
|
|
179
|
+
if (this.pageInline) {
|
|
180
|
+
this.show = true;
|
|
181
|
+
}
|
|
182
|
+
},
|
|
183
|
+
methods: {
|
|
184
|
+
// 判断SKU是否被选中
|
|
185
|
+
isSelected(skuKey, skuValueId) {
|
|
186
|
+
return this.selectedSku[skuKey] === skuValueId
|
|
187
|
+
},
|
|
188
|
+
// 判断SKU是否禁用
|
|
189
|
+
isDisabled(skuKey, skuValueId) {
|
|
190
|
+
// 构造一个临时的已选中SKU对象
|
|
191
|
+
const tempSelected = { ...this.selectedSku, [skuKey]: skuValueId }
|
|
192
|
+
|
|
193
|
+
// 检查是否还有未选择的SKU维度
|
|
194
|
+
const selectedCount = Object.keys(tempSelected).filter(key => tempSelected[key]).length
|
|
195
|
+
const totalSkuCount = this.skuTree.length
|
|
196
|
+
|
|
197
|
+
// 如果所有SKU都已选择,则检查组合是否存在
|
|
198
|
+
if (selectedCount === totalSkuCount) {
|
|
199
|
+
return !this.getSkuComb(tempSelected)
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// 检查当前选择的SKU是否会导致无法组成有效组合
|
|
203
|
+
for (let i = 0; i < this.skuList.length; i++) {
|
|
204
|
+
const sku = this.skuList[i]
|
|
205
|
+
let match = true
|
|
206
|
+
|
|
207
|
+
// 检查已选中的SKU是否匹配
|
|
208
|
+
for (const key in tempSelected) {
|
|
209
|
+
if (tempSelected[key] && sku[key] !== tempSelected[key]) {
|
|
210
|
+
match = false
|
|
211
|
+
break
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
if (match) {
|
|
216
|
+
return false
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
return true
|
|
221
|
+
},
|
|
222
|
+
// SKU点击事件
|
|
223
|
+
onSkuClick(skuKey, skuValue) {
|
|
224
|
+
// 如果是禁用状态,直接返回
|
|
225
|
+
if (this.isDisabled(skuKey, skuValue.id)) {
|
|
226
|
+
return
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
// 如果已选中,则取消选中
|
|
230
|
+
if (this.selectedSku[skuKey] === skuValue.id) {
|
|
231
|
+
this.$set(this.selectedSku, skuKey, '')
|
|
232
|
+
} else {
|
|
233
|
+
this.$set(this.selectedSku, skuKey, skuValue.id)
|
|
234
|
+
}
|
|
235
|
+
},
|
|
236
|
+
// 数量改变事件
|
|
237
|
+
onNumChange(e) {
|
|
238
|
+
this.buyNum = e.value
|
|
239
|
+
},
|
|
240
|
+
// 获取选中的SKU组合
|
|
241
|
+
getSelectedSkuComb() {
|
|
242
|
+
return this.getSkuComb(this.selectedSku)
|
|
243
|
+
},
|
|
244
|
+
// 根据已选SKU获取组合信息
|
|
245
|
+
getSkuComb(selectedSku) {
|
|
246
|
+
const selected = { ...selectedSku }
|
|
247
|
+
|
|
248
|
+
// 过滤掉空值
|
|
249
|
+
Object.keys(selected).forEach(key => {
|
|
250
|
+
if (!selected[key]) {
|
|
251
|
+
delete selected[key]
|
|
252
|
+
}
|
|
253
|
+
})
|
|
254
|
+
|
|
255
|
+
// 检查是否所有SKU都已选择
|
|
256
|
+
if (Object.keys(selected).length !== this.skuTree.length) {
|
|
257
|
+
return null
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
// 查找匹配的SKU组合
|
|
261
|
+
for (let i = 0; i < this.skuList.length; i++) {
|
|
262
|
+
const sku = this.skuList[i]
|
|
263
|
+
let match = true
|
|
264
|
+
|
|
265
|
+
for (const key in selected) {
|
|
266
|
+
if (sku[key] !== selected[key]) {
|
|
267
|
+
match = false
|
|
268
|
+
break
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
if (match) {
|
|
273
|
+
return sku
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
return null
|
|
278
|
+
},
|
|
279
|
+
// 重置选择
|
|
280
|
+
reset() {
|
|
281
|
+
this.selectedSku = {}
|
|
282
|
+
this.buyNum = 1
|
|
283
|
+
},
|
|
284
|
+
open() {
|
|
285
|
+
this.show = true;
|
|
286
|
+
this.$emit('open')
|
|
287
|
+
},
|
|
288
|
+
// 关闭弹窗
|
|
289
|
+
close() {
|
|
290
|
+
this.false = true;
|
|
291
|
+
this.$emit('close')
|
|
292
|
+
},
|
|
293
|
+
// 确认选择
|
|
294
|
+
onConfirm() {
|
|
295
|
+
if (!this.canBuy) {
|
|
296
|
+
return
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
const selectedSkuComb = this.getSelectedSkuComb()
|
|
300
|
+
this.$emit('confirm', {
|
|
301
|
+
sku: selectedSkuComb,
|
|
302
|
+
goodsInfo: this.goodsInfo,
|
|
303
|
+
num: this.buyNum,
|
|
304
|
+
selectedText: this.selectedSkuText
|
|
305
|
+
})
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
</script>
|
|
310
|
+
|
|
311
|
+
<style lang="scss" scoped>
|
|
312
|
+
.up-goods-sku {
|
|
313
|
+
background-color: #fff;
|
|
314
|
+
overflow: hidden;
|
|
315
|
+
|
|
316
|
+
.up-goods-sku-container {
|
|
317
|
+
padding: 4rpx 30rpx;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
&__header {
|
|
321
|
+
display: flex;
|
|
322
|
+
flex-direction: row;
|
|
323
|
+
padding: 30rpx 0;
|
|
324
|
+
position: relative;
|
|
325
|
+
|
|
326
|
+
&__image {
|
|
327
|
+
width: 180rpx;
|
|
328
|
+
height: 180rpx;
|
|
329
|
+
border-radius: 10rpx;
|
|
330
|
+
overflow: hidden;
|
|
331
|
+
margin-right: 20rpx;
|
|
332
|
+
|
|
333
|
+
image {
|
|
334
|
+
width: 100%;
|
|
335
|
+
height: 100%;
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
&__info {
|
|
340
|
+
flex: 1;
|
|
341
|
+
|
|
342
|
+
&__price {
|
|
343
|
+
display: flex;
|
|
344
|
+
flex-direction: row;
|
|
345
|
+
align-items: baseline;
|
|
346
|
+
margin-bottom: 20rpx;
|
|
347
|
+
|
|
348
|
+
&__symbol {
|
|
349
|
+
font-size: 24rpx;
|
|
350
|
+
color: #fa3534;
|
|
351
|
+
margin-right: 4rpx;
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
&__value {
|
|
355
|
+
font-size: 36rpx;
|
|
356
|
+
color: #fa3534;
|
|
357
|
+
font-weight: bold;
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
&__stock {
|
|
362
|
+
font-size: 26rpx;
|
|
363
|
+
color: #999;
|
|
364
|
+
margin-bottom: 20rpx;
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
&__selected {
|
|
368
|
+
font-size: 26rpx;
|
|
369
|
+
color: #333;
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
&__content {
|
|
375
|
+
max-height: 600rpx;
|
|
376
|
+
padding: 0 30rpx 30rpx 0;
|
|
377
|
+
|
|
378
|
+
&__item {
|
|
379
|
+
margin-bottom: 30rpx;
|
|
380
|
+
|
|
381
|
+
&__title {
|
|
382
|
+
font-size: 28rpx;
|
|
383
|
+
color: #333;
|
|
384
|
+
margin-bottom: 20rpx;
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
&__list {
|
|
388
|
+
display: flex;
|
|
389
|
+
flex-direction: row;
|
|
390
|
+
flex-wrap: wrap;
|
|
391
|
+
|
|
392
|
+
&__item {
|
|
393
|
+
padding: 10rpx 20rpx;
|
|
394
|
+
border: 2rpx solid #eee;
|
|
395
|
+
border-radius: 10rpx;
|
|
396
|
+
margin-right: 20rpx;
|
|
397
|
+
margin-bottom: 20rpx;
|
|
398
|
+
font-size: 26rpx;
|
|
399
|
+
color: #333;
|
|
400
|
+
|
|
401
|
+
&--active {
|
|
402
|
+
border-color: #fa3534;
|
|
403
|
+
color: #fa3534;
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
&--disabled {
|
|
407
|
+
color: #ccc;
|
|
408
|
+
border-color: #eee;
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
&__count {
|
|
415
|
+
display: flex;
|
|
416
|
+
flex-direction: row;
|
|
417
|
+
align-items: center;
|
|
418
|
+
justify-content: space-between;
|
|
419
|
+
margin-top: 20rpx;
|
|
420
|
+
|
|
421
|
+
&__title {
|
|
422
|
+
font-size: 28rpx;
|
|
423
|
+
color: #333;
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
&__footer {
|
|
429
|
+
padding: 20rpx 0rpx 40rpx 0;
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
</style>
|
|
@@ -21,10 +21,13 @@ export default {
|
|
|
21
21
|
safeAreaInsetBottom: true,
|
|
22
22
|
safeAreaInsetTop: false,
|
|
23
23
|
closeIconPos: 'top-right',
|
|
24
|
-
round:
|
|
24
|
+
round: '20px',
|
|
25
25
|
zoom: true,
|
|
26
26
|
bgColor: '',
|
|
27
27
|
overlayOpacity: 0.5,
|
|
28
|
-
pageInline: false
|
|
28
|
+
pageInline: false,
|
|
29
|
+
touchable: false,
|
|
30
|
+
minHeight: '200px',
|
|
31
|
+
maxHeight: '600px'
|
|
29
32
|
}
|
|
30
33
|
}
|
|
@@ -81,6 +81,21 @@ export const props = defineMixin({
|
|
|
81
81
|
pageInline:{
|
|
82
82
|
type: Boolean,
|
|
83
83
|
default: () => defProps.popup.pageInline
|
|
84
|
+
},
|
|
85
|
+
// 是否页开启手势滑动
|
|
86
|
+
touchable:{
|
|
87
|
+
type: Boolean,
|
|
88
|
+
default: () => defProps.popup.touchable
|
|
89
|
+
},
|
|
90
|
+
// 手势滑动最小高度
|
|
91
|
+
minHeight:{
|
|
92
|
+
type: [String],
|
|
93
|
+
default: () => defProps.popup.minHeight
|
|
94
|
+
},
|
|
95
|
+
// 手势滑动最大高度
|
|
96
|
+
maxHeight:{
|
|
97
|
+
type: [String],
|
|
98
|
+
default: () => defProps.popup.maxHeight
|
|
84
99
|
}
|
|
85
100
|
}
|
|
86
101
|
})
|
|
@@ -18,7 +18,9 @@
|
|
|
18
18
|
:opacity="overlayOpacity"
|
|
19
19
|
></u-overlay>
|
|
20
20
|
<u-transition
|
|
21
|
-
|
|
21
|
+
class="u-popup__content—transition"
|
|
22
|
+
:style="contentStyleWrap"
|
|
23
|
+
:show="pageInline ? true : show"
|
|
22
24
|
:customStyle="transitionStyle"
|
|
23
25
|
:mode="pageInline ? 'none' : position"
|
|
24
26
|
:duration="duration"
|
|
@@ -33,6 +35,18 @@
|
|
|
33
35
|
@touchmove.stop.prevent="noop"
|
|
34
36
|
>
|
|
35
37
|
<u-status-bar v-if="safeAreaInsetTop"></u-status-bar>
|
|
38
|
+
<!-- 增加触摸区域,用于处理手势 -->
|
|
39
|
+
<view
|
|
40
|
+
v-if="touchable && mode === 'bottom'"
|
|
41
|
+
class="u-popup__content__touch-area"
|
|
42
|
+
@touchstart="onTouchStart"
|
|
43
|
+
@touchmove="onTouchMove"
|
|
44
|
+
@touchend="onTouchEnd"
|
|
45
|
+
@touchcancel="onTouchEnd"
|
|
46
|
+
>
|
|
47
|
+
<!-- iOS风格的横条指示器 -->
|
|
48
|
+
<view class="u-popup__content__indicator"></view>
|
|
49
|
+
</view>
|
|
36
50
|
<slot></slot>
|
|
37
51
|
<view
|
|
38
52
|
v-if="closeable"
|
|
@@ -78,9 +92,12 @@
|
|
|
78
92
|
* @property {Boolean} safeAreaInsetBottom 是否为iPhoneX留出底部安全距离 (默认 true )
|
|
79
93
|
* @property {Boolean} safeAreaInsetTop 是否留出顶部安全距离(状态栏高度) (默认 false )
|
|
80
94
|
* @property {String} closeIconPos 自定义关闭图标位置(默认 'top-right' )
|
|
81
|
-
* @property {String | Number} round 圆角值(默认
|
|
95
|
+
* @property {String | Number} round 圆角值(默认 20px)
|
|
82
96
|
* @property {String } bgColor 背景色值(默认 '' )
|
|
83
97
|
* @property {Boolean} zoom 当mode=center时 是否开启缩放(默认 true )
|
|
98
|
+
* @property {Boolean} touchable 是否开启底部弹窗手势功能(默认 false )
|
|
99
|
+
* @property {String} minHeight 最小高度,单位任意,数值默认为px(默认 '200px' )
|
|
100
|
+
* @property {String} maxHeight 最大高度,单位任意,数值默认为px(默认 '80%' )
|
|
84
101
|
* @property {Object} customStyle 组件的样式,对象形式
|
|
85
102
|
* @event {Function} open 弹出层打开
|
|
86
103
|
* @event {Function} close 弹出层收起
|
|
@@ -91,7 +108,13 @@
|
|
|
91
108
|
mixins: [mpMixin, mixin, props],
|
|
92
109
|
data() {
|
|
93
110
|
return {
|
|
94
|
-
overlayDuration: this.duration + 50
|
|
111
|
+
overlayDuration: this.duration + 50,
|
|
112
|
+
// 触摸相关数据
|
|
113
|
+
touchStartY: 0,
|
|
114
|
+
touchStartHeight: 0,
|
|
115
|
+
isTouching: false,
|
|
116
|
+
// 当前弹窗高度
|
|
117
|
+
currentHeight: 'auto'
|
|
95
118
|
}
|
|
96
119
|
},
|
|
97
120
|
watch: {
|
|
@@ -145,6 +168,23 @@
|
|
|
145
168
|
})
|
|
146
169
|
}
|
|
147
170
|
},
|
|
171
|
+
contentStyleWrap() {
|
|
172
|
+
const style = {}
|
|
173
|
+
|
|
174
|
+
// 处理手势滑动时的高度变化
|
|
175
|
+
if (this.mode === 'bottom' && this.touchable) {
|
|
176
|
+
if (this.currentHeight !== 'auto') {
|
|
177
|
+
style.height = this.currentHeight
|
|
178
|
+
}
|
|
179
|
+
if (this.maxHeight) {
|
|
180
|
+
style.maxHeight = addUnit(this.maxHeight)
|
|
181
|
+
}
|
|
182
|
+
if (this.minHeight) {
|
|
183
|
+
style.minHeight = addUnit(this.minHeight)
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
return style;
|
|
187
|
+
},
|
|
148
188
|
contentStyle() {
|
|
149
189
|
const style = {}
|
|
150
190
|
// 通过设备信息的safeAreaInsets值来判断是否需要预留顶部状态栏和底部安全局的位置
|
|
@@ -171,6 +211,7 @@
|
|
|
171
211
|
style.borderRadius = value
|
|
172
212
|
}
|
|
173
213
|
}
|
|
214
|
+
|
|
174
215
|
return deepMerge(style, addStyle(this.customStyle))
|
|
175
216
|
},
|
|
176
217
|
position() {
|
|
@@ -242,8 +283,61 @@
|
|
|
242
283
|
this.retryComputedComponentRect(grandChild)
|
|
243
284
|
}
|
|
244
285
|
}
|
|
245
|
-
}
|
|
286
|
+
},
|
|
246
287
|
// #endif
|
|
288
|
+
|
|
289
|
+
// 触摸开始
|
|
290
|
+
onTouchStart(e) {
|
|
291
|
+
if (!this.touchable || this.mode !== 'bottom') return;
|
|
292
|
+
this.isTouching = true;
|
|
293
|
+
this.touchStartY = e.touches[0].clientY;
|
|
294
|
+
// 保存当前高度
|
|
295
|
+
this.touchStartHeight = this.$el.querySelector('.u-popup__content—transition').offsetHeight;
|
|
296
|
+
},
|
|
297
|
+
|
|
298
|
+
// 触摸移动
|
|
299
|
+
onTouchMove(e) {
|
|
300
|
+
if (!this.isTouching || !this.touchable || this.mode !== 'bottom') return;
|
|
301
|
+
const touchY = e.touches[0].clientY;
|
|
302
|
+
const deltaY = touchY - this.touchStartY;
|
|
303
|
+
|
|
304
|
+
// 只处理向上滑动(减小高度)和向下滑动(增加高度)
|
|
305
|
+
if (deltaY !== 0) {
|
|
306
|
+
const newHeight = this.touchStartHeight - deltaY;
|
|
307
|
+
const minHeight = parseFloat(addUnit(this.minHeight)) || 200;
|
|
308
|
+
const maxHeight = this.maxHeight ?
|
|
309
|
+
(this.maxHeight.toString().includes('%') ?
|
|
310
|
+
getWindowInfo().windowHeight * (parseFloat(this.maxHeight) / 100) :
|
|
311
|
+
parseFloat(addUnit(this.maxHeight))) :
|
|
312
|
+
getWindowInfo().windowHeight * 0.8;
|
|
313
|
+
|
|
314
|
+
// 限制高度在最小值和最大值之间
|
|
315
|
+
if (newHeight >= minHeight && newHeight <= maxHeight) {
|
|
316
|
+
this.currentHeight = newHeight + 'px';
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
// 阻止默认滚动行为
|
|
321
|
+
e.preventDefault();
|
|
322
|
+
},
|
|
323
|
+
|
|
324
|
+
// 触摸结束
|
|
325
|
+
onTouchEnd(e) {
|
|
326
|
+
if (!this.isTouching || !this.touchable || this.mode !== 'bottom') return;
|
|
327
|
+
this.isTouching = false;
|
|
328
|
+
|
|
329
|
+
const touchY = e.changedTouches[0].clientY;
|
|
330
|
+
const deltaY = touchY - this.touchStartY;
|
|
331
|
+
const velocity = Math.abs(deltaY) / (e.timeStamp - e.changedTouches[0].timestamp); // 简单的速度计算
|
|
332
|
+
|
|
333
|
+
// 快速向下滑动时关闭弹窗
|
|
334
|
+
if (deltaY > 100 || (deltaY > 30 && velocity > 0.5)) {
|
|
335
|
+
this.close();
|
|
336
|
+
} else {
|
|
337
|
+
// 恢复到自适应高度
|
|
338
|
+
// this.currentHeight = 'auto';
|
|
339
|
+
}
|
|
340
|
+
}
|
|
247
341
|
}
|
|
248
342
|
}
|
|
249
343
|
</script>
|
|
@@ -304,6 +398,27 @@
|
|
|
304
398
|
border-bottom-left-radius: 10px;
|
|
305
399
|
border-bottom-right-radius: 10px;
|
|
306
400
|
}
|
|
401
|
+
|
|
402
|
+
&__touch-area {
|
|
403
|
+
// position: absolute;
|
|
404
|
+
top: 0;
|
|
405
|
+
left: 0;
|
|
406
|
+
right: 0;
|
|
407
|
+
height: 42rpx;
|
|
408
|
+
z-index: 10;
|
|
409
|
+
/* #ifndef APP-NVUE */
|
|
410
|
+
display: flex;
|
|
411
|
+
/* #endif */
|
|
412
|
+
justify-content: center;
|
|
413
|
+
align-items: center;
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
&__indicator {
|
|
417
|
+
width: 100px;
|
|
418
|
+
height: 5px;
|
|
419
|
+
border-radius: 100px;
|
|
420
|
+
background-color: #c0c4cc;
|
|
421
|
+
}
|
|
307
422
|
|
|
308
423
|
&__close {
|
|
309
424
|
position: absolute;
|
|
@@ -334,4 +449,4 @@
|
|
|
334
449
|
}
|
|
335
450
|
}
|
|
336
451
|
}
|
|
337
|
-
</style>
|
|
452
|
+
</style>
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"id": "uview-plus",
|
|
3
3
|
"name": "uview-plus",
|
|
4
4
|
"displayName": "零云®uview-plus3.0重磅发布,全面的Vue3鸿蒙跨端移动组件库,组件丰富维护更新稳定。",
|
|
5
|
-
"version": "3.5.
|
|
5
|
+
"version": "3.5.22",
|
|
6
6
|
"description": "零云®uview-plus已兼容vue3支持多语言,100+全面的组件和便捷的工具会让您信手拈来。近期新增拖动排序、条码、图片裁剪、下拉刷新、虚拟列表、签名、Markdown等。",
|
|
7
7
|
"keywords": [
|
|
8
8
|
"uview",
|