xydata-tools 1.0.44 → 1.0.46
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/dist/components/uni-app/file-picker/file-picker.vue +11 -4
- package/dist/components/uni-app/file-picker/styles.scss +15 -20
- package/dist/components/uni-app/media-picker/media-picker.vue +62 -23
- package/dist/components/uni-app/media-picker/shmily-drag-media.vue +137 -46
- package/dist/components/uni-app/media-picker/styles.scss +460 -459
- package/package.json +1 -1
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
</view>
|
|
39
39
|
<view class="file-actions">
|
|
40
40
|
<view class="action-btn delete-btn" @click="removeFile(index)">
|
|
41
|
-
|
|
41
|
+
×
|
|
42
42
|
</view>
|
|
43
43
|
</view>
|
|
44
44
|
</view>
|
|
@@ -57,7 +57,7 @@
|
|
|
57
57
|
</view>
|
|
58
58
|
</view>
|
|
59
59
|
</view>
|
|
60
|
-
</view>
|
|
60
|
+
</view>
|
|
61
61
|
</view>
|
|
62
62
|
</template>
|
|
63
63
|
|
|
@@ -178,8 +178,6 @@ export default {
|
|
|
178
178
|
case 'jpeg':
|
|
179
179
|
case 'jpg':
|
|
180
180
|
case 'gif':
|
|
181
|
-
case 'webp':
|
|
182
|
-
case 'svg':
|
|
183
181
|
return require('../../../assets/file-icon/image.png')
|
|
184
182
|
case 'mp4':
|
|
185
183
|
case 'mov':
|
|
@@ -515,6 +513,15 @@ export default {
|
|
|
515
513
|
const ext = this.getFileExtension(file.name)
|
|
516
514
|
const supportedTypes = ['doc', 'xls', 'ppt', 'pdf', 'docx', 'xlsx', 'pptx']
|
|
517
515
|
const isDocument = supportedTypes.includes(ext)
|
|
516
|
+
|
|
517
|
+
const imageTypes = ['png', 'jpeg', 'jpg', 'gif']
|
|
518
|
+
console.log(ext)
|
|
519
|
+
if (imageTypes.includes(ext)) {
|
|
520
|
+
uni.previewImage({
|
|
521
|
+
urls: [file.url]
|
|
522
|
+
})
|
|
523
|
+
return
|
|
524
|
+
}
|
|
518
525
|
|
|
519
526
|
// 显示加载提示
|
|
520
527
|
uni.showLoading({
|
|
@@ -72,31 +72,26 @@
|
|
|
72
72
|
|
|
73
73
|
.file-actions {
|
|
74
74
|
margin-left: 16rpx;
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
height: 44rpx;
|
|
81
|
-
border-radius: 50%;
|
|
82
|
-
display: flex;
|
|
83
|
-
align-items: center;
|
|
84
|
-
justify-content: center;
|
|
85
|
-
background-color: rgba(0, 0, 0, 0.6);
|
|
75
|
+
position: relative;
|
|
76
|
+
width: 40rpx;
|
|
77
|
+
height: 40rpx;
|
|
78
|
+
border-radius: 50%;
|
|
79
|
+
background-color: rgba(0, 0, 0, 0.6);
|
|
86
80
|
|
|
81
|
+
.delete-btn {
|
|
82
|
+
color: #fff;
|
|
83
|
+
font-size: 32rpx;
|
|
84
|
+
line-height: 1;
|
|
85
|
+
font-weight: 300;
|
|
86
|
+
position: absolute;
|
|
87
|
+
top: 50%;
|
|
88
|
+
left: 50%;
|
|
89
|
+
transform: translate(-50%, -50%);
|
|
90
|
+
padding-bottom: 2px;
|
|
87
91
|
&:active {
|
|
88
92
|
opacity: 0.8;
|
|
89
93
|
}
|
|
90
94
|
}
|
|
91
|
-
|
|
92
|
-
.delete-btn {
|
|
93
|
-
.delete-icon {
|
|
94
|
-
color: #fff;
|
|
95
|
-
font-size: 32rpx;
|
|
96
|
-
line-height: 0.1;
|
|
97
|
-
font-weight: 300;
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
95
|
}
|
|
101
96
|
|
|
102
97
|
.progress-bar {
|
|
@@ -8,8 +8,7 @@
|
|
|
8
8
|
<view v-if="enableImage && showFileList" class="media-section">
|
|
9
9
|
<shmily-drag-media v-if="imageFileList.length > 0" v-model="imageUrls" :number="imageLimit"
|
|
10
10
|
:cols="cols" :imageWidth="itemWidth" :padding="10" :borderRadius="itemBorderRadius"
|
|
11
|
-
:
|
|
12
|
-
@update:modelValue="handleImageDragChange">
|
|
11
|
+
:draggable="draggable" moveType="image" @update:modelValue="handleImageDragChange">
|
|
13
12
|
</shmily-drag-media>
|
|
14
13
|
</view>
|
|
15
14
|
|
|
@@ -18,8 +17,8 @@
|
|
|
18
17
|
:style="{ marginTop: enableImage && videoFileList.length > 0 ? '20rpx' : '0' }">
|
|
19
18
|
<shmily-drag-media v-if="videoFileList.length > 0" v-model="videoUrls" :number="videoLimit"
|
|
20
19
|
:cols="cols" :imageWidth="itemWidth" :padding="10" :borderRadius="itemBorderRadius"
|
|
21
|
-
:
|
|
22
|
-
@
|
|
20
|
+
:draggable="draggable" moveType="video" @update:modelValue="handleVideoDragChange"
|
|
21
|
+
@videoClick="handleVideoItemClick">
|
|
23
22
|
</shmily-drag-media>
|
|
24
23
|
</view>
|
|
25
24
|
|
|
@@ -29,8 +28,8 @@
|
|
|
29
28
|
<view v-if="enableImage" class="upload-button-wrapper">
|
|
30
29
|
<slot name="image-upload-button" :select="selectAndUploadImage" :limit="imageLimit"
|
|
31
30
|
:count="imageFileList.length">
|
|
32
|
-
<view class="upload-btn-vertical"
|
|
33
|
-
@click="selectAndUploadImage">
|
|
31
|
+
<view class="upload-btn-vertical" :style="{ borderRadius: itemBorderRadius + 'rpx' }"
|
|
32
|
+
v-if="imageFileList.length < imageLimit" @click="selectAndUploadImage">
|
|
34
33
|
<image :src="imageUploadIcon" class="upload-icon"></image>
|
|
35
34
|
<view class="upload-text">{{ imageButtonTitle }}</view>
|
|
36
35
|
</view>
|
|
@@ -41,8 +40,8 @@
|
|
|
41
40
|
<view v-if="enableVideo" class="upload-button-wrapper">
|
|
42
41
|
<slot name="video-upload-button" :select="selectAndUploadVideo" :limit="videoLimit"
|
|
43
42
|
:count="videoFileList.length">
|
|
44
|
-
<view class="upload-btn-vertical"
|
|
45
|
-
@click="selectAndUploadVideo">
|
|
43
|
+
<view class="upload-btn-vertical" :style="{ borderRadius: itemBorderRadius + 'rpx' }"
|
|
44
|
+
v-if="videoFileList.length < videoLimit" @click="selectAndUploadVideo">
|
|
46
45
|
<image :src="videoUploadIcon" class="upload-icon"></image>
|
|
47
46
|
<view class="upload-text">{{ videoButtonTitle }}</view>
|
|
48
47
|
</view>
|
|
@@ -58,14 +57,14 @@
|
|
|
58
57
|
:number="imageLimit" :cols="cols" :imageWidth="itemWidth" :padding="10"
|
|
59
58
|
:borderRadius="itemBorderRadius" :align="align" :draggable="draggable" :enableAddButton="true"
|
|
60
59
|
moveType="image" @update:modelValue="handleImageDragChange" @add-click="selectAndUploadImage">
|
|
61
|
-
<template #add-button>
|
|
60
|
+
<template #add-button="{ childWidth }">
|
|
62
61
|
<slot name="image-upload-button" :select="selectAndUploadImage" :limit="imageLimit"
|
|
63
62
|
:count="imageFileList.length">
|
|
64
63
|
<view class="drag-upload-btn">
|
|
65
64
|
<image :src="imageUploadIcon" class="upload-icon"
|
|
66
|
-
:style="
|
|
67
|
-
<view class="upload-text" :style="{
|
|
68
|
-
|
|
65
|
+
:style="getUploadIconStyle(childWidth)"></image>
|
|
66
|
+
<view class="upload-text" :style="getUploadTextStyle(childWidth)">{{ imageButtonTitle }}
|
|
67
|
+
</view>
|
|
69
68
|
</view>
|
|
70
69
|
</slot>
|
|
71
70
|
</template>
|
|
@@ -77,14 +76,14 @@
|
|
|
77
76
|
:borderRadius="itemBorderRadius" :align="align" :draggable="draggable" :enableAddButton="true"
|
|
78
77
|
moveType="video" @update:modelValue="handleVideoDragChange" @add-click="selectAndUploadVideo"
|
|
79
78
|
@videoClick="handleVideoItemClick">
|
|
80
|
-
<template #add-button>
|
|
79
|
+
<template #add-button="{ childWidth }">
|
|
81
80
|
<slot name="video-upload-button" :select="selectAndUploadVideo" :limit="videoLimit"
|
|
82
81
|
:count="videoFileList.length">
|
|
83
82
|
<view class="drag-upload-btn">
|
|
84
83
|
<image :src="videoUploadIcon" class="upload-icon"
|
|
85
|
-
:style="
|
|
86
|
-
<view class="upload-text" :style="{
|
|
87
|
-
|
|
84
|
+
:style="getUploadIconStyle(childWidth)"></image>
|
|
85
|
+
<view class="upload-text" :style="getUploadTextStyle(childWidth)">{{ videoButtonTitle }}
|
|
86
|
+
</view>
|
|
88
87
|
</view>
|
|
89
88
|
</slot>
|
|
90
89
|
</template>
|
|
@@ -197,8 +196,8 @@ export default {
|
|
|
197
196
|
// ==================== 通用配置 ====================
|
|
198
197
|
/** 上传类型: 'image' - 仅图片, 'video' - 仅视频, 'both' - 图片+视频(必填) */
|
|
199
198
|
uploadType: {
|
|
200
|
-
type: String,
|
|
201
|
-
|
|
199
|
+
type: String,
|
|
200
|
+
default: 'image',
|
|
202
201
|
validator: (value) => ['image', 'video', 'both'].includes(value)
|
|
203
202
|
},
|
|
204
203
|
/** 上传地址 */
|
|
@@ -335,6 +334,7 @@ export default {
|
|
|
335
334
|
popupAnimated: false,
|
|
336
335
|
mediaLoadingStatus: {},
|
|
337
336
|
fullscreenVideoSrc: '', // 专门用于全屏播放的视频源
|
|
337
|
+
windowWidth: uni.getSystemInfoSync ? uni.getSystemInfoSync().windowWidth : 375,
|
|
338
338
|
}
|
|
339
339
|
},
|
|
340
340
|
computed: {
|
|
@@ -458,11 +458,8 @@ export default {
|
|
|
458
458
|
|
|
459
459
|
// ==================== 弹窗模式网格样式 ====================
|
|
460
460
|
popupGridStyle() {
|
|
461
|
-
// 如果指定了 itemWidth,使用固定宽度;否则使用 1fr 自动分配
|
|
462
|
-
const columnWidth = this.itemWidth ? `${this.itemWidth}rpx` : '1fr'
|
|
463
|
-
|
|
464
461
|
return {
|
|
465
|
-
gridTemplateColumns: `repeat(${this.cols},
|
|
462
|
+
gridTemplateColumns: `repeat(${this.cols}, 1fr)`,
|
|
466
463
|
gap: '10rpx'
|
|
467
464
|
}
|
|
468
465
|
}
|
|
@@ -496,6 +493,48 @@ export default {
|
|
|
496
493
|
hasEventListener(eventName) {
|
|
497
494
|
return !!(this.$listeners && this.$listeners[eventName])
|
|
498
495
|
},
|
|
496
|
+
parseChildWidth(childWidth) {
|
|
497
|
+
if (typeof childWidth === 'number') {
|
|
498
|
+
return childWidth
|
|
499
|
+
}
|
|
500
|
+
if (typeof childWidth === 'string') {
|
|
501
|
+
const parsed = parseFloat(childWidth)
|
|
502
|
+
return Number.isFinite(parsed) ? parsed : null
|
|
503
|
+
}
|
|
504
|
+
return null
|
|
505
|
+
},
|
|
506
|
+
pxToRpx(px) {
|
|
507
|
+
if (!px || !this.windowWidth) {
|
|
508
|
+
return 0
|
|
509
|
+
}
|
|
510
|
+
return px / this.windowWidth * 750
|
|
511
|
+
},
|
|
512
|
+
computeUploadIconSize(childWidth) {
|
|
513
|
+
const parsedPx = this.parseChildWidth(childWidth)
|
|
514
|
+
if (!parsedPx) {
|
|
515
|
+
return this.uploadIconSize
|
|
516
|
+
}
|
|
517
|
+
const widthRpx = this.pxToRpx(parsedPx)
|
|
518
|
+
const size = Math.floor(widthRpx * 0.3)
|
|
519
|
+
return Math.max(20, size)
|
|
520
|
+
},
|
|
521
|
+
computeUploadTextSize(childWidth) {
|
|
522
|
+
const iconSize = this.computeUploadIconSize(childWidth)
|
|
523
|
+
const size = Math.floor(iconSize * 0.4)
|
|
524
|
+
return Math.max(20, size)
|
|
525
|
+
},
|
|
526
|
+
getUploadIconStyle(childWidth) {
|
|
527
|
+
const size = this.computeUploadIconSize(childWidth)
|
|
528
|
+
return {
|
|
529
|
+
width: size + 'rpx',
|
|
530
|
+
height: size + 'rpx'
|
|
531
|
+
}
|
|
532
|
+
},
|
|
533
|
+
getUploadTextStyle(childWidth) {
|
|
534
|
+
return {
|
|
535
|
+
fontSize: this.computeUploadTextSize(childWidth) + 'rpx'
|
|
536
|
+
}
|
|
537
|
+
},
|
|
499
538
|
|
|
500
539
|
// ==================== 图片相关方法 ====================
|
|
501
540
|
/**
|
|
@@ -1018,7 +1057,7 @@ export default {
|
|
|
1018
1057
|
showCount: this.maxShowCount,
|
|
1019
1058
|
hiddenCount: this.allFileList.length - this.maxShowCount,
|
|
1020
1059
|
allFiles: this.allFileList
|
|
1021
|
-
})
|
|
1060
|
+
})
|
|
1022
1061
|
|
|
1023
1062
|
if (!this.hasEventListener('moreClick')) {
|
|
1024
1063
|
this.openPopup()
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
<template v-if="viewWidth">
|
|
4
4
|
<movable-area class="area" :style="{ height: areaHeight }" @mouseenter="mouseenter"
|
|
5
5
|
@mouseleave="mouseleave">
|
|
6
|
-
<movable-view
|
|
6
|
+
<movable-view v-for="(item, index) in imageList" :key="item.id" class="view" direction="all" :y="item.y"
|
|
7
7
|
:x="item.x" :damping="40" :disabled="!draggable" @change="onChange($event, item)"
|
|
8
8
|
@touchstart="touchstart(item)" @mousedown="touchstart(item)" @touchend="touchend($event, item)"
|
|
9
9
|
@mouseup="touchend($event, item)" :style="{
|
|
@@ -18,9 +18,14 @@
|
|
|
18
18
|
borderRadius: borderRadius + 'rpx',
|
|
19
19
|
transform: 'scale(' + item.scale + ')'
|
|
20
20
|
}">
|
|
21
|
-
<image v-if="moveType === 'image'" class="pre-image" :src="item.src" mode="aspectFill"
|
|
21
|
+
<image v-if="moveType === 'image'" class="pre-image" :src="item.src" mode="aspectFill"
|
|
22
|
+
@load="handleMediaLoad(item)" @error="handleMediaError(item)"></image>
|
|
22
23
|
<video v-else-if="moveType === 'video'" :id="'readonlyVideo' + index" class="myVideo"
|
|
23
|
-
:src="item.src" :controls="false" :show-center-play-btn="true" object-fit="cover"
|
|
24
|
+
:src="item.src" :controls="false" :show-center-play-btn="true" object-fit="cover"
|
|
25
|
+
@loadedmetadata="handleMediaLoad(item)" @error="handleMediaError(item)"></video>
|
|
26
|
+
<view class="media-loading-overlay" v-if="item.loading">
|
|
27
|
+
<view class="loading-spinner"></view>
|
|
28
|
+
</view>
|
|
24
29
|
<view class="del-con" @click="delImages(item, index)" @touchstart.stop="delImageMp(item, index)"
|
|
25
30
|
@touchend.stop="nothing()" @mousedown.stop="nothing()" @mouseup.stop="nothing()">
|
|
26
31
|
<view class="del-wrap">
|
|
@@ -37,12 +42,7 @@
|
|
|
37
42
|
@click="addImages">
|
|
38
43
|
<view class="add-wrap"
|
|
39
44
|
:style="{ width: childWidth, height: childWidth, borderRadius: borderRadius + 'rpx' }">
|
|
40
|
-
<slot name="add-button" :childWidth="childWidth" :borderRadius="borderRadius">
|
|
41
|
-
<!-- 默认添加按钮 -->
|
|
42
|
-
<image style="width: 54rpx;height: 54rpx;"
|
|
43
|
-
src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADYAAAA2CAYAAACMRWrdAAABIUlEQVRoQ+2a2w2DMAxFeQzWrsMUbadAsEw3S1CqVgppKwLX8BEOP4iHTXx8uUgWdVXoVhdaV0VhSmf7vr/H8V3XzY6V3P9iD+nYOI5P7/01LMI596AwoZV0TIBXIUWFXhKLFBWYSFGhhxQN6SFFQ5i4ogITKSr0cEVDekjRECauqMBEigq9U7piOk2yAti27SUe5ljlTfPEQ6KZecTvwl4P3ytvOv06R2HDMNzes7+6aRrvnHvtf50L13Lp50rx88zcvNlS3JpwKQ67XyK04nq2nFbk/LqVjin0TvmBNgQ2S4UUDcliHgpMpKjQwxUN6SFFQ5i4ogITKSr0cEVDekjRECauqMAsVoph+hVPtYr5+03p9tbYQ96xrYtT4ootbAJGVxxVTapVswAAAABJRU5ErkJggg==">
|
|
44
|
-
</image>
|
|
45
|
-
</slot>
|
|
45
|
+
<slot name="add-button" :childWidth="childWidth" :borderRadius="borderRadius"></slot>
|
|
46
46
|
</view>
|
|
47
47
|
</view>
|
|
48
48
|
</movable-area>
|
|
@@ -129,28 +129,30 @@ export default {
|
|
|
129
129
|
type: Boolean,
|
|
130
130
|
default: false
|
|
131
131
|
},
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
132
|
+
// 对齐方式:'left' 从左往右排列,'right' 从右往左排列
|
|
133
|
+
align: {
|
|
134
|
+
type: String,
|
|
135
|
+
default: 'left',
|
|
136
|
+
validator: (value) => ['left', 'right'].includes(value)
|
|
137
|
+
},
|
|
138
|
+
// 是否可以拖拽排序
|
|
139
|
+
draggable: {
|
|
140
|
+
type: Boolean,
|
|
141
|
+
default: true
|
|
142
|
+
},
|
|
143
|
+
},
|
|
144
144
|
data() {
|
|
145
145
|
return {
|
|
146
146
|
imageList: [],
|
|
147
147
|
width: 0,
|
|
148
|
+
containerWidth: 0,
|
|
148
149
|
add: {
|
|
149
150
|
x: 0,
|
|
150
151
|
y: 0
|
|
151
152
|
},
|
|
152
153
|
colsValue: 0,
|
|
153
154
|
viewWidth: 0,
|
|
155
|
+
rightAlignOffset: 0,
|
|
154
156
|
tempItem: null,
|
|
155
157
|
timer: null,
|
|
156
158
|
changeStatus: true,
|
|
@@ -221,6 +223,14 @@ export default {
|
|
|
221
223
|
},
|
|
222
224
|
deep: true
|
|
223
225
|
},
|
|
226
|
+
align() {
|
|
227
|
+
this.updateRightAlignOffset()
|
|
228
|
+
if (!this.viewWidth || !this.colsValue) {
|
|
229
|
+
return
|
|
230
|
+
}
|
|
231
|
+
this.recalculateAllPositions()
|
|
232
|
+
this.updateAddButtonPosition()
|
|
233
|
+
}
|
|
224
234
|
},
|
|
225
235
|
created() {
|
|
226
236
|
this.width = uni.getSystemInfoSync().windowWidth
|
|
@@ -228,12 +238,17 @@ export default {
|
|
|
228
238
|
mounted() {
|
|
229
239
|
const query = uni.createSelectorQuery().in(this)
|
|
230
240
|
query.select('.con').boundingClientRect(data => {
|
|
241
|
+
this.containerWidth = data.width
|
|
231
242
|
this.colsValue = this.cols
|
|
232
243
|
this.viewWidth = data.width / this.cols
|
|
233
244
|
if (this.imageWidth > 0) {
|
|
234
245
|
this.viewWidth = this.rpx2px(this.imageWidth)
|
|
235
246
|
this.colsValue = Math.floor(data.width / this.viewWidth)
|
|
236
247
|
}
|
|
248
|
+
if (this.colsValue < 1) {
|
|
249
|
+
this.colsValue = 1
|
|
250
|
+
}
|
|
251
|
+
this.updateRightAlignOffset()
|
|
237
252
|
let list = this.value
|
|
238
253
|
// #ifdef VUE3
|
|
239
254
|
list = this.modelValue
|
|
@@ -259,7 +274,7 @@ export default {
|
|
|
259
274
|
*/
|
|
260
275
|
calculatePosition(index, total) {
|
|
261
276
|
const absY = Math.floor(index / this.colsValue)
|
|
262
|
-
|
|
277
|
+
|
|
263
278
|
if (this.align === 'right') {
|
|
264
279
|
// 靠右对齐:计算当前行的元素数量(包括按钮),然后从右往左排列
|
|
265
280
|
const currentRowItemCount = Math.min(total - absY * this.colsValue, this.colsValue)
|
|
@@ -273,7 +288,25 @@ export default {
|
|
|
273
288
|
return { absX, absY }
|
|
274
289
|
}
|
|
275
290
|
},
|
|
276
|
-
|
|
291
|
+
getRightOffset() {
|
|
292
|
+
return this.align === 'right' ? this.rightAlignOffset : 0
|
|
293
|
+
},
|
|
294
|
+
getAlignedX(absX) {
|
|
295
|
+
return this.getRightOffset() + absX * this.viewWidth
|
|
296
|
+
},
|
|
297
|
+
updateRightAlignOffset() {
|
|
298
|
+
if (!this.viewWidth || !this.colsValue || !this.containerWidth) {
|
|
299
|
+
this.rightAlignOffset = 0
|
|
300
|
+
return
|
|
301
|
+
}
|
|
302
|
+
if (this.align !== 'right') {
|
|
303
|
+
this.rightAlignOffset = 0
|
|
304
|
+
return
|
|
305
|
+
}
|
|
306
|
+
const theoreticalWidth = this.viewWidth * this.colsValue
|
|
307
|
+
this.rightAlignOffset = Math.max(0, this.containerWidth - theoreticalWidth)
|
|
308
|
+
},
|
|
309
|
+
|
|
277
310
|
/**
|
|
278
311
|
* 获取总数(如果显示添加按钮,则包括按钮)
|
|
279
312
|
*/
|
|
@@ -284,7 +317,7 @@ export default {
|
|
|
284
317
|
}
|
|
285
318
|
return this.imageList.length
|
|
286
319
|
},
|
|
287
|
-
|
|
320
|
+
|
|
288
321
|
getSrc(item) {
|
|
289
322
|
if (this.keyName !== null) {
|
|
290
323
|
return item[this.keyName]
|
|
@@ -297,10 +330,14 @@ export default {
|
|
|
297
330
|
item.oldY = e.detail.y
|
|
298
331
|
if (e.detail.source === 'touch') {
|
|
299
332
|
if (item.moveEnd) {
|
|
300
|
-
item.offset = Math.sqrt(Math.pow(item.oldX - item.absX
|
|
333
|
+
item.offset = Math.sqrt(Math.pow(item.oldX - this.getAlignedX(item.absX), 2) + Math.pow(item.oldY - item
|
|
301
334
|
.absY * this.viewWidth, 2))
|
|
302
335
|
}
|
|
303
|
-
|
|
336
|
+
const offsetX = this.getRightOffset()
|
|
337
|
+
let x = Math.floor((e.detail.x - offsetX + this.viewWidth / 2) / this.viewWidth)
|
|
338
|
+
if (x < 0) {
|
|
339
|
+
x = 0
|
|
340
|
+
}
|
|
304
341
|
if (x >= this.colsValue) return
|
|
305
342
|
let y = Math.floor((e.detail.y + this.viewWidth / 2) / this.viewWidth)
|
|
306
343
|
let index = this.colsValue * y + x
|
|
@@ -317,8 +354,10 @@ export default {
|
|
|
317
354
|
obj.y = obj.oldY
|
|
318
355
|
setTimeout(() => {
|
|
319
356
|
this.$nextTick(() => {
|
|
320
|
-
obj.x = obj.absX
|
|
357
|
+
obj.x = this.getAlignedX(obj.absX)
|
|
321
358
|
obj.y = obj.absY * this.viewWidth
|
|
359
|
+
obj.oldX = obj.x
|
|
360
|
+
obj.oldY = obj.y
|
|
322
361
|
})
|
|
323
362
|
}, 0)
|
|
324
363
|
}
|
|
@@ -331,8 +370,10 @@ export default {
|
|
|
331
370
|
if (!item.moveEnd) {
|
|
332
371
|
setTimeout(() => {
|
|
333
372
|
this.$nextTick(() => {
|
|
334
|
-
item.x = item.absX
|
|
373
|
+
item.x = this.getAlignedX(item.absX)
|
|
335
374
|
item.y = item.absY * this.viewWidth
|
|
375
|
+
item.oldX = item.x
|
|
376
|
+
item.oldY = item.y
|
|
336
377
|
})
|
|
337
378
|
}, 0)
|
|
338
379
|
}
|
|
@@ -351,8 +392,10 @@ export default {
|
|
|
351
392
|
obj.absY = pos.absY
|
|
352
393
|
setTimeout(() => {
|
|
353
394
|
this.$nextTick(() => {
|
|
354
|
-
obj.x = obj.absX
|
|
395
|
+
obj.x = this.getAlignedX(obj.absX)
|
|
355
396
|
obj.y = obj.absY * this.viewWidth
|
|
397
|
+
obj.oldX = obj.x
|
|
398
|
+
obj.oldY = obj.y
|
|
356
399
|
})
|
|
357
400
|
}, 0)
|
|
358
401
|
},
|
|
@@ -361,7 +404,7 @@ export default {
|
|
|
361
404
|
if (!this.draggable) {
|
|
362
405
|
return
|
|
363
406
|
}
|
|
364
|
-
|
|
407
|
+
|
|
365
408
|
this.imageList.forEach(v => {
|
|
366
409
|
v.zIndex = v.index + 9
|
|
367
410
|
})
|
|
@@ -383,7 +426,7 @@ export default {
|
|
|
383
426
|
this.lastTouchEndTime = Date.now()
|
|
384
427
|
} else if (eventType === 'mouseup') {
|
|
385
428
|
// 如果 100ms 内已经处理过 touchend,则忽略此 mouseup(避免重复)
|
|
386
|
-
if (this.lastTouchEndTime && Date.now() - this.lastTouchEndTime < 100) {
|
|
429
|
+
if (this.lastTouchEndTime && Date.now() - this.lastTouchEndTime < 100) {
|
|
387
430
|
if (this.timer) {
|
|
388
431
|
clearTimeout(this.timer)
|
|
389
432
|
this.timer = null
|
|
@@ -415,8 +458,10 @@ export default {
|
|
|
415
458
|
item.moveEnd = false
|
|
416
459
|
setTimeout(() => {
|
|
417
460
|
this.$nextTick(() => {
|
|
418
|
-
item.x = item.absX
|
|
461
|
+
item.x = this.getAlignedX(item.absX)
|
|
419
462
|
item.y = item.absY * this.viewWidth
|
|
463
|
+
item.oldX = item.x
|
|
464
|
+
item.oldY = item.y
|
|
420
465
|
this.tempItem = null
|
|
421
466
|
this.changeStatus = true
|
|
422
467
|
})
|
|
@@ -473,8 +518,10 @@ export default {
|
|
|
473
518
|
v.x = v.oldX
|
|
474
519
|
v.y = v.oldY
|
|
475
520
|
this.$nextTick(() => {
|
|
476
|
-
v.x = v.absX
|
|
521
|
+
v.x = this.getAlignedX(v.absX)
|
|
477
522
|
v.y = v.absY * this.viewWidth
|
|
523
|
+
v.oldX = v.x
|
|
524
|
+
v.oldY = v.y
|
|
478
525
|
this.tempItem = null
|
|
479
526
|
})
|
|
480
527
|
}
|
|
@@ -526,7 +573,7 @@ export default {
|
|
|
526
573
|
const pos = this.calculatePosition(i, totalWithButton)
|
|
527
574
|
obj.absX = pos.absX
|
|
528
575
|
obj.absY = pos.absY
|
|
529
|
-
const newX = obj.absX
|
|
576
|
+
const newX = this.getAlignedX(obj.absX)
|
|
530
577
|
const newY = obj.absY * this.viewWidth
|
|
531
578
|
|
|
532
579
|
// 如果位置有变化,才进行动画
|
|
@@ -584,7 +631,7 @@ export default {
|
|
|
584
631
|
},
|
|
585
632
|
addProperties(item) {
|
|
586
633
|
const newIndex = this.imageList.length
|
|
587
|
-
|
|
634
|
+
|
|
588
635
|
// 先添加图片到列表
|
|
589
636
|
this.imageList.push({
|
|
590
637
|
src: item,
|
|
@@ -601,9 +648,10 @@ export default {
|
|
|
601
648
|
id: this.guid(16),
|
|
602
649
|
disable: false,
|
|
603
650
|
offset: 0,
|
|
604
|
-
moveEnd: false
|
|
651
|
+
moveEnd: false,
|
|
652
|
+
loading: true
|
|
605
653
|
})
|
|
606
|
-
|
|
654
|
+
|
|
607
655
|
// 如果是右对齐且显示按钮,添加新图片后需要重新计算所有图片位置
|
|
608
656
|
if (this.align === 'right' && this.showAddButton) {
|
|
609
657
|
this.recalculateAllPositions()
|
|
@@ -614,15 +662,15 @@ export default {
|
|
|
614
662
|
const obj = this.imageList[newIndex]
|
|
615
663
|
obj.absX = pos.absX
|
|
616
664
|
obj.absY = pos.absY
|
|
617
|
-
obj.x = pos.absX
|
|
665
|
+
obj.x = this.getAlignedX(pos.absX)
|
|
618
666
|
obj.y = pos.absY * this.viewWidth
|
|
619
667
|
obj.oldX = obj.x
|
|
620
668
|
obj.oldY = obj.y
|
|
621
669
|
}
|
|
622
|
-
|
|
670
|
+
|
|
623
671
|
this.updateAddButtonPosition()
|
|
624
672
|
},
|
|
625
|
-
|
|
673
|
+
|
|
626
674
|
/**
|
|
627
675
|
* 重新计算所有图片的位置(用于右对齐时添加/删除图片)
|
|
628
676
|
*/
|
|
@@ -630,9 +678,9 @@ export default {
|
|
|
630
678
|
const totalWithButton = this.getTotalCount()
|
|
631
679
|
this.imageList.forEach((obj, i) => {
|
|
632
680
|
const pos = this.calculatePosition(i, totalWithButton)
|
|
633
|
-
const newX = pos.absX
|
|
681
|
+
const newX = this.getAlignedX(pos.absX)
|
|
634
682
|
const newY = pos.absY * this.viewWidth
|
|
635
|
-
|
|
683
|
+
|
|
636
684
|
// 如果位置有变化,进行动画过渡
|
|
637
685
|
if (obj.absX !== pos.absX || obj.absY !== pos.absY) {
|
|
638
686
|
obj.x = obj.oldX
|
|
@@ -674,19 +722,29 @@ export default {
|
|
|
674
722
|
return
|
|
675
723
|
}
|
|
676
724
|
const length = this.imageList.length
|
|
677
|
-
|
|
725
|
+
|
|
678
726
|
if (this.align === 'right' && this.showAddButton) {
|
|
679
727
|
// 右对齐且显示按钮:按钮的位置就是"虚拟的第 length 个元素"的位置
|
|
680
728
|
// 总数包括按钮本身
|
|
681
729
|
const totalWithButton = length + 1
|
|
682
730
|
const pos = this.calculatePosition(length, totalWithButton)
|
|
683
|
-
this.add.x = pos.absX
|
|
731
|
+
this.add.x = this.getAlignedX(pos.absX) + 'px'
|
|
684
732
|
this.add.y = pos.absY * this.viewWidth + 'px'
|
|
685
733
|
} else {
|
|
686
734
|
// 左对齐或不显示按钮:按钮直接跟在最后一个元素后面
|
|
687
|
-
|
|
688
|
-
|
|
735
|
+
const absX = length % this.colsValue
|
|
736
|
+
const absY = Math.floor(length / this.colsValue)
|
|
737
|
+
this.add.x = this.getAlignedX(absX) + 'px'
|
|
738
|
+
this.add.y = absY * this.viewWidth + 'px'
|
|
689
739
|
}
|
|
740
|
+
},
|
|
741
|
+
handleMediaLoad(item) {
|
|
742
|
+
if (!item) return
|
|
743
|
+
item.loading = false
|
|
744
|
+
},
|
|
745
|
+
handleMediaError(item) {
|
|
746
|
+
if (!item) return
|
|
747
|
+
item.loading = false
|
|
690
748
|
}
|
|
691
749
|
}
|
|
692
750
|
}
|
|
@@ -735,6 +793,29 @@ export default {
|
|
|
735
793
|
}
|
|
736
794
|
}
|
|
737
795
|
|
|
796
|
+
.media-loading-overlay {
|
|
797
|
+
position: absolute;
|
|
798
|
+
top: 0;
|
|
799
|
+
left: 0;
|
|
800
|
+
right: 0;
|
|
801
|
+
bottom: 0;
|
|
802
|
+
display: flex;
|
|
803
|
+
align-items: center;
|
|
804
|
+
justify-content: center;
|
|
805
|
+
background-color: rgba(0, 0, 0, 0.05);
|
|
806
|
+
border-radius: inherit;
|
|
807
|
+
z-index: 5;
|
|
808
|
+
}
|
|
809
|
+
|
|
810
|
+
.loading-spinner {
|
|
811
|
+
width: 40rpx;
|
|
812
|
+
height: 40rpx;
|
|
813
|
+
border: 4rpx solid rgba(0, 0, 0, 0.1);
|
|
814
|
+
border-top-color: #007aff;
|
|
815
|
+
border-radius: 50%;
|
|
816
|
+
animation: spinner-rotate 0.8s linear infinite;
|
|
817
|
+
}
|
|
818
|
+
|
|
738
819
|
.del-con {
|
|
739
820
|
position: absolute;
|
|
740
821
|
top: 0rpx;
|
|
@@ -774,4 +855,14 @@ export default {
|
|
|
774
855
|
}
|
|
775
856
|
}
|
|
776
857
|
}
|
|
858
|
+
|
|
859
|
+
@keyframes spinner-rotate {
|
|
860
|
+
0% {
|
|
861
|
+
transform: rotate(0deg);
|
|
862
|
+
}
|
|
863
|
+
|
|
864
|
+
100% {
|
|
865
|
+
transform: rotate(360deg);
|
|
866
|
+
}
|
|
867
|
+
}
|
|
777
868
|
</style>
|