私人定制:阿里oss上传组件
本文代码只是vue前端组件代码,还需要依赖vuedraggable组件库(支持拖拽排序);还需要ossUpload.js工具函数(详见另外一文:阿里oss上传工具)
该组件写的时候大部分都是参照elementUI的上传组件(其实是本来的业务代码都是通过后端上传,后面领导说要用oss,所以就写了这个组件),所以使用到了elementUI的部分组件
1 <template> 2 <div> 3 <div class="flex-wrap"> 4 <div class="oss-upload"> 5 <slot></slot> 6 <label v-if="!disabled" class="hand"> 7 <input 8 :multiple="multiple" 9 type="file" 10 class="hidden" 11 @change="change" 12 /> 13 </label> 14 </div> 15 16 <el-button 17 v-if="!disabled && onDelete && value" 18 @click="handleDelete" 19 type="text" 20 size="small" 21 >删除</el-button 22 > 23 24 <slot name="tips"> 25 <span class="tips">{{ tips }}</span> 26 </slot> 27 </div> 28 <draggable 29 class="drag-list" 30 v-if="!disabled && showFileList && filelist.length > 0" 31 v-model="filelist" 32 @change="drag" 33 > 34 <div class="drag-item" v-for="(item, idx) in filelist" :key="idx"> 35 <img class="drag-item-img" :src="item" /> 36 <i class="el-icon-error" @click="remove(idx)"></i> 37 </div> 38 </draggable> 39 <template v-else-if="showFileList && filelist.length > 0"> 40 <div class="drag-list"> 41 <div class="drag-item" v-for="(item, idx) in filelist" :key="idx"> 42 <img class="drag-item-img" :src="item" /> 43 </div> 44 </div> 45 </template> 46 </div> 47 </template> 48 49 <script> 50 import draggable from "vuedraggable"; 51 import { uploadOSS, defaultLimit } from "@/utils/ossUpload"; 52 export default { 53 components: { 54 draggable, 55 }, 56 props: { 57 value: String, 58 limit: [String, Number], 59 maxCount: [String, Number], 60 tips: String, 61 disabled: { 62 type: Boolean, 63 default: false, 64 }, 65 compress: { 66 type: Boolean, 67 default: false, 68 }, 69 showUploadResult: { 70 type: Boolean, 71 default: true, 72 }, 73 multiple: { 74 type: Boolean, 75 default: false, 76 }, 77 showFileList: { 78 type: Boolean, 79 default: false, 80 }, 81 fileList: { 82 type: Array, 83 default: () => [], 84 }, 85 onBeforeUpload: { 86 type: Function, 87 default: () => {}, 88 }, 89 onSuccess: { 90 type: Function, 91 default: () => {}, 92 }, 93 onError: { 94 type: Function, 95 default: () => {}, 96 }, 97 onChange: { 98 type: Function, 99 default: () => {}, 100 }, 101 onDelete: { 102 type: Function, 103 default: null, 104 }, 105 dir: { 106 type: String, 107 default: "file", 108 }, 109 }, 110 watch: { 111 fileList: { 112 handler(val) { 113 this.filelist = val || []; 114 }, 115 immediate: true, 116 }, 117 }, 118 data() { 119 return { 120 filelist: [], 121 }; 122 }, 123 methods: { 124 clearFileList() { 125 this.filelist = []; 126 }, 127 handleDelete() { 128 this.onDelete && this.onDelete(); 129 }, 130 remove(index) { 131 this.filelist = this.filelist.filter((item, idx) => idx !== index); 132 this.onChange(this.filelist); 133 }, 134 drag() { 135 this.onChange(this.filelist); 136 }, 137 change(e) { 138 const files = Array.from(e.target.files); 139 const limit = Number(this.limit); 140 const maxCount = Number(this.maxCount); 141 if (maxCount === maxCount) { 142 // maxCount值有效,则限制数量 143 if (this.filelist.length + files.length > maxCount) { 144 this.$message.warning(`最多上传${maxCount}张图片`); 145 return; 146 } 147 } 148 // 限制图片类型 149 const _files = files.filter((d) => { 150 if (d.type == "image/png" || d.type == "image/jpeg") { 151 return true; 152 } else { 153 return false; 154 } 155 }); 156 e.target.value = null; 157 158 // 存在不符合的图片类型 159 if (_files.length !== files.length) { 160 this.$message.warning("图片类型不是png或者jpeg"); 161 } 162 // 没有有效的图片直接返回 163 if (_files.length === 0) { 164 return; 165 } 166 this.onBeforeUpload(); // 上传前钩子 167 uploadOSS(_files, this.dir, { 168 limitSize: isNaN(limit) ? defaultLimit : limit, 169 compress: this.compress, 170 }) 171 .then(({ result, code, msg }) => { 172 this.showUploadResult && 173 this.$message({ 174 type: code == 1 ? "success" : "warning", 175 message: msg, 176 }); 177 result.forEach((res) => { 178 this.filelist.push(res.url); 179 }); 180 181 if (this.multiple || this.filelist[this.filelist.length - 1]) { 182 this.onSuccess( 183 result, 184 this.multiple 185 ? this.filelist 186 : this.filelist[this.filelist.length - 1] 187 ); 188 } 189 }) 190 .catch((err) => { 191 console.error(err); 192 this.onError(err); 193 }); 194 }, 195 }, 196 }; 197 </script> 198 199 <style scoped> 200 .oss-upload img { 201 display: block; 202 } 203 .flex-wrap { 204 display: inline-flex; 205 align-items: center; 206 } 207 .oss-upload { 208 display: inline-block; 209 position: relative; 210 margin-right: 10px; 211 } 212 .hand { 213 z-index: 99; 214 cursor: pointer; 215 position: absolute; 216 top: 0; 217 left: 0; 218 right: 0; 219 bottom: 0; 220 } 221 .hidden { 222 display: none; 223 } 224 225 .el-icon-error { 226 position: absolute; 227 right: -7px; 228 top: -7px; 229 font-size: 18px; 230 cursor: pointer; 231 color: #f56c6c; 232 } 233 .drag-list { 234 display: flex; 235 flex-wrap: wrap; 236 padding: 20px 0; 237 } 238 .drag-item { 239 position: relative; 240 margin-right: 10px; 241 } 242 243 .drag-item-img { 244 object-fit: contain; 245 width: 100px; 246 height: 100px; 247 border: 1px solid #ddd; 248 border-radius: 4px; 249 } 250 251 .tips { 252 font-size: 12px; 253 color: #999; 254 } 255 </style>