2
2
Component: UploadImgs
3
3
Describe: 多图片上传组件, 附有预览, 排序, 验证等功能
4
4
5
- todo: 文档编写
6
- todo: jsDoc 编写
7
- todo: 图像验证支持是否动图验证
8
5
todo: 使用中间件模式优化信息装载和验证功能
9
6
todo: 文件判断使用 serveWorker 优化性能
10
7
-->
@@ -24,18 +21,10 @@ todo: 文件判断使用 serveWorker 优化性能
24
21
:fit =" fit"
25
22
style =" width : 100% ; height : 100% ;" ></el-image >
26
23
<div class =" info" >
27
- <i
28
- v-if =" item.file"
29
- class =" el-icon-upload wait-upload"
30
- @click.prevent.stop =" delItem(item.id)"
31
- title =" 等待上传" ></i >
24
+ <i v-if =" item.file" class =" el-icon-upload wait-upload" @click.prevent.stop =" delItem(item.id)" title =" 等待上传" ></i >
32
25
</div >
33
26
<div class =" control" >
34
- <i
35
- v-if =" !disabled"
36
- class =" el-icon-close del"
37
- @click.prevent.stop =" delItem(item.id)"
38
- title =" 删除" ></i >
27
+ <i v-if =" !disabled" class =" el-icon-close del" @click.prevent.stop =" delItem(item.id)" title =" 删除" ></i >
39
28
<div
40
29
v-if =" !disabled"
41
30
class =" preview"
@@ -44,24 +33,9 @@ todo: 文件判断使用 serveWorker 优化性能
44
33
<i class =" el-icon-edit" ></i >
45
34
</div >
46
35
<div class =" control-bottom" v-if =" sortable || preview" >
47
- <i
48
- v-if =" sortable && !disabled"
49
- title =" 前移"
50
- class =" control-bottom-btn el-icon-back"
51
- :class =" {disabled: (i === 0)}"
52
- @click.stop =" move(item.id, -1)" ></i >
53
- <i
54
- v-if =" preview"
55
- class =" control-bottom-btn el-icon-view"
56
- title =" 预览"
57
- style =" cursor : pointer ;"
58
- @click.stop =" previewImg(item, i)" ></i >
59
- <i
60
- v-if =" sortable && !disabled"
61
- title =" 后移"
62
- class =" control-bottom-btn el-icon-right"
63
- :class =" {disabled: (i === (itemList.length - 1))}"
64
- @click.stop =" move(item.id, 1)" ></i >
36
+ <i v-if =" sortable && !disabled" title =" 前移" class =" control-bottom-btn el-icon-back" :class =" {disabled: (i === 0)}" @click.stop =" move(item.id, -1)" ></i >
37
+ <i v-if =" preview" class =" control-bottom-btn el-icon-view" title =" 预览" style =" cursor : pointer ;" @click.stop =" previewImg(item, i)" ></i >
38
+ <i v-if =" sortable && !disabled" title =" 后移" class =" control-bottom-btn el-icon-right" :class =" {disabled: (i === (itemList.length - 1))}" @click.stop =" move(item.id, 1)" ></i >
65
39
</div >
66
40
</div >
67
41
</div >
@@ -79,13 +53,7 @@ todo: 文件判断使用 serveWorker 优化性能
79
53
</div >
80
54
</template >
81
55
</template >
82
- <input
83
- class =" upload-imgs__input"
84
- type =" file"
85
- ref =" input"
86
- @change =" handleChange"
87
- :multiple =" multiple"
88
- :accept =" accept" />
56
+ <input class =" upload-imgs__input" type =" file" ref =" input" @change =" handleChange" :multiple =" multiple" :accept =" accept" />
89
57
</div >
90
58
</template >
91
59
@@ -108,22 +76,37 @@ import {
108
76
* @property {number} size 文件大小
109
77
* @property {string} type 文件的媒体类型 (MIME)
110
78
* @property {Date} lastModified 文件最后修改时间
79
+ * @property {boolean} isAnimated 是否是动态图, 如果不进行检测则为 null
111
80
*/
112
81
113
82
/**
114
83
* 返回数据对象
84
+ * 初始化的图片如果没有传入字段, 则值为空 null
115
85
* @typedef {Object<string, number>} ReturnItem
116
- * @property {number|string} id 本地图像预览地址
117
- * @property {number|string} imgId 宽
86
+ * @property {number|string} id 初始化数据的 id
87
+ * @property {number|string} imgId 图像资源 id
118
88
* @property {string} src 文件相对路径
119
- * @property {string} display 文件完整路径
89
+ * @property {string} display 图像完整地址
120
90
* @property {number} height 高
121
91
* @property {number} width 宽
122
92
* @property {string} fileName 文件名
123
93
* @property {string} fileType 文件的媒体类型 (MIME), 针对部分文件类型做了检测
124
94
* @property {boolean} isAnimated 是否是动态图, 如果不进行检测则为 null
125
95
*/
126
96
97
+ /**
98
+ * 返回数据对象
99
+ * @typedef {Object} ValidateRule
100
+ * @property {array|number} ratio 比例 [宽,高], 或者 宽/高 的数值
101
+ * @property {number} width 宽度必需等于
102
+ * @property {number} height 高度必需等于
103
+ * @property {number} minWidth 最小宽
104
+ * @property {number} minHeight 最小高
105
+ * @property {number} minSize 最小 size(Mb)
106
+ * @property {number} maxSize 最大 size(Mb)
107
+ * @property {number} allowAnimated 是否允许上传动图, 0 不检测, 1 不允许动图, 2 只允许动图. 要检查此项, 需设置属性 animated-check 为 true
108
+ */
109
+
127
110
const ONE_KB = 1024
128
111
const ONE_MB = ONE_KB * 1024
129
112
@@ -279,7 +262,9 @@ export default {
279
262
/** 图像验证规则 */
280
263
rules: {
281
264
type: [Object , Function ],
282
- default : () => {},
265
+ default : () => ({
266
+ maxSize: 2 ,
267
+ }),
283
268
},
284
269
/** 是否禁用, 禁用后只可展示 不可进行编辑操作, 包括: 新增, 修改, 删除, 改变顺序 */
285
270
disabled: {
@@ -388,7 +373,7 @@ export default {
388
373
basicRule = {}
389
374
}
390
375
} else {
391
- basicRule = rules
376
+ basicRule = rules || {}
392
377
}
393
378
394
379
// 宽高限制提示语
@@ -419,6 +404,15 @@ export default {
419
404
tips .push (getRangeTip (' 文件大小' , basicRule .minSize , basicRule .maxSize , ' Mb' ))
420
405
}
421
406
407
+ // 是否动态图
408
+ if (basicRule .allowAnimated && basicRule .allowAnimated > 0 ) {
409
+ if (basicRule .allowAnimated === 1 ) {
410
+ tips .push (' 不允许上传动图' )
411
+ } else if (basicRule .allowAnimated === 1 ) {
412
+ tips .push (' 只允许上传动图' )
413
+ }
414
+ }
415
+
422
416
return tips
423
417
},
424
418
},
@@ -526,7 +520,7 @@ export default {
526
520
// eslint-disable-next-line
527
521
imgItem .display = res .url
528
522
// eslint-disable-next-line
529
- imgItem .src = res .url
523
+ imgItem .src = res .path
530
524
// eslint-disable-next-line
531
525
imgItem .imgId = res .id
532
526
// eslint-disable-next-line
@@ -655,14 +649,15 @@ export default {
655
649
/** @type {ReturnItem} */
656
650
const val = {
657
651
id: item .status === ' new' ? ' ' : item .id ,
658
- imgId: item .imgId ,
659
- src: item .src ,
652
+ imgId: item .imgId || null ,
653
+ src: item .src || null ,
660
654
display: item .display ,
661
- width: item .width ,
662
- height: item .height ,
663
- fileName: item .name ,
664
- fileType: item .type ,
665
- isAnimated: item .isAnimated ,
655
+ width: item .width || null ,
656
+ height: item .height || null ,
657
+ fileSize: item .size || null ,
658
+ fileName: item .name || null ,
659
+ fileType: item .type || null ,
660
+ isAnimated: item .isAnimated || null ,
666
661
}
667
662
return val
668
663
})
@@ -738,10 +733,11 @@ export default {
738
733
},
739
734
/**
740
735
* 验证上传的图像是否符合要求
741
- * @param {Object} 图像信息, 包括文件名, 宽高
736
+ * @param {LocalFileInfo} imgInfo 图像信息, 包括文件名, 宽高
742
737
*/
743
738
async validateImg (imgInfo ) {
744
739
const { rules } = this
740
+ /** @type ValidateRule */
745
741
let rule
746
742
// 针对动态规则模式, 获取输入为空时的规则
747
743
// 动态规则 rule 为函数, 当选择图片后根据选择的图片生成校验规则
@@ -754,6 +750,20 @@ export default {
754
750
} else {
755
751
rule = rules
756
752
}
753
+
754
+ if (rule .allowAnimated && rule .allowAnimated > 0 ) {
755
+ if (imgInfo .isAnimated === null ) {
756
+ this .$message .error (' 要进行是否动图验证需要配置 "animated-check" 属性为 true' )
757
+ } else {
758
+ if (rule .allowAnimated === 1 && imgInfo .isAnimated ) {
759
+ throw new Error (` "${ imgInfo .name } "为动态图, 不允许上传` )
760
+ }
761
+ if (rule .allowAnimated === 2 && ! imgInfo .isAnimated ) {
762
+ throw new Error (` "${ imgInfo .name } "为静态图, 只允许上传动态图` )
763
+ }
764
+ }
765
+ }
766
+
757
767
// 宽高限制
758
768
if (rule .width ) {
759
769
if (imgInfo .width !== rule .width ) {
@@ -1009,6 +1019,10 @@ export default {
1009
1019
this .initItemList ([])
1010
1020
this .getValue ()
1011
1021
},
1022
+ /** 重置图片数据传入属性 */
1023
+ reset () {
1024
+ this .initItemList (this .value )
1025
+ },
1012
1026
},
1013
1027
}
1014
1028
</script >
0 commit comments