功能:支持预览、长按图片保存、删除
项目中使用:
1 <el-form-item label="上传照片" class="ml30"> 2 <e-upload-image 3 v-model="image" 4 @change="fileList => handleImageChange(fileList)" 5 tip="(注:最多上传10张图片,每张大小不超过20M)" 6 :acceptData="{ maxsize: 1024 * 1024 * 20, maxsize_text: '20M' }" 7 > 8 </e-upload-image> 9 </el-form-item> 10 11 12 handleImageChange(fileList) { 13 this.image = fileList 14 }
注册组件 src/components/index.js
1 import EUploadImage from './EUploadImage' 2 3 export default { 4 install(Vue) { 5 Vue.component('EUploadImage', EUploadImage) 6 } 7 }
main.js引入自定义组件:
import Components from '@/components/index' Vue.use(Components)
二次封装好的上传图片的组件 EUploadImage.vue:
1 <template> 2 <!-- 上传图片,支持预览、下载、删除 --> 3 <div class="any-upload-image"> 4 <el-upload 5 :action="uploadApi()" 6 list-type="picture-card" 7 :data="acceptData" 8 :limit="limit" 9 multiple 10 :accept="accept" 11 :file-list="fileList" 12 :on-exceed="handleExceed" 13 :on-success="(response, file, fileList) => handleSuccess(response, file, fileList)" 14 :before-upload="file => beforeUpload(file)" 15 > 16 <i class="el-icon-plus"></i> 17 <div slot="file" slot-scope="{ file }" class="file-container"> 18 <img class="el-upload-list__item-thumbnail" :src="getFileAccessHttpUrl(file.url)" alt="" /> 19 <span class="el-upload-list__item-actions"> 20 <!-- 预览 --> 21 <span class="el-upload-list__item-preview" @click="handlePreview(file)"> 22 <i class="el-icon-zoom-in"></i> 23 </span> 24 <!-- 删除 --> 25 <span v-if="!acceptData.disabledRemove" class="el-upload-list__item-delete" @click="handleRemove(file)"> 26 <i class="el-icon-delete"></i> 27 </span> 28 </span> 29 </div> 30 </el-upload> 31 32 <!-- 预览图片 --> 33 <div v-show="previewVisible" class="custom-box-img" :class="typeof dark !== 'undefined' ? 'dark' : ''"> 34 <i class="el-icon-close" @click="previewVisible = false"></i> 35 <div class="img-con custom-mobile-scroll"> 36 <img :src="imageUrl" @touchstart="down(imageUrl, currentFile)" @touchmove="up" @touchend="up" /> 37 <!-- 保存 --> 38 <div v-if="!acceptData.disabledDownload" class="download-icon" @click="handleDownload(currentFile)"> 39 <el-button type="primary" size="mini" icon="el-icon-download">保存</el-button> 40 </div> 41 </div> 42 </div> 43 <!-- 提示 --> 44 <el-row class="limit-tip"> 45 <span>{{ tip }}</span> 46 </el-row> 47 </div> 48 </template> 49 50 51 <script> 52 const uidGenerator = () => { 53 return '-' + parseInt(Math.random() * 10000 + 1, 10) 54 } 55 56 57 const getFileName = path => { 58 if (path.lastIndexOf('\\') >= 0) { 59 let reg = new RegExp('\\\\', 'g') 60 path = path.replace(reg, '/') 61 } 62 return path.substring(path.lastIndexOf('/') + 1) 63 } 64 65 export default { 66 name: 'EUploadImage', 67 props: { 68 value: { 69 type: [String, Array], 70 required: false 71 }, 72 73 // 文件类型 74 accept: { 75 type: String, 76 default: 'image/png, image/jpg, image/gif, image/jpeg' 77 }, 78 79 // 上传时附带的额外参数 80 acceptData: { 81 type: Object, 82 default: () => { 83 return { 84 maxsize: 1024 * 1024 * 20, 85 maxsize_text: '20M', 86 disabledDownload: false, 87 disabledRemove: false 88 } 89 } 90 }, 91 92 // 提示 93 tip: { 94 type: String, 95 default: '' 96 }, 97 98 // 最大数量 99 limit: { 100 type: Number, 101 default: 10 102 }, 103 104 // 黑色模式 105 dark: {} 106 }, 107 108 watch: { 109 value: { 110 handler(val, oldValue) { 111 this.initFileList(val) 112 }, 113 // 立刻执行handler 114 immediate: true 115 } 116 }, 117 118 data() { 119 return { 120 previewVisible: false, // 预览图片弹框显隐 121 imageUrl: '', // 预览图片的地址 122 fileList: [], 123 currentFile: '' 124 } 125 }, 126 127 methods: { 128 initFileList(array) { 129 if (!array || array.length == 0) { 130 this.fileList = [] 131 return 132 } 133 134 let fileList = [] 135 let arr = array 136 for (let a = 0; a < arr.length; a++) { 137 let url = this.getFileAccessHttpUrl(arr[a].url) 138 fileList.push({ 139 uid: uidGenerator(), 140 name: getFileName(arr[a].name), 141 status: 'done', 142 url: url, 143 response: { 144 status: 'history', 145 message: url 146 } 147 }) 148 } 149 this.fileList = fileList 150 }, 151 152 getFileAccessHttpUrl(url) { 153 if (url.indexOf('/dispatch') > -1) { 154 return url 155 } else { 156 return '/dispatch' + url 157 } 158 }, 159 160 // 上传文件地址 161 uploadApi() { 162 return '/dispatch/upload' 163 }, 164 165 // 其他附件上传大小限制处理 166 beforeUpload(file) { 167 const isLessThanMaxSize = file.size < this.acceptData.maxsize 168 if (!isLessThanMaxSize) { 169 this.$toast(`上传文件大小不能超过${this.acceptData.maxsize_text}!`) 170 } 171 return isLessThanMaxSize 172 }, 173 174 // 文件个数限制 175 handleExceed() { 176 this.$toast(`当前限制最多上传 ${this.limit} 个文件!`) 177 }, 178 179 // 上传图片成功 180 handleSuccess(response, file, fileList) { 181 if (response.code == 200) { 182 this.$toast('上传成功') 183 let attachment = fileList.map(item => { 184 let url = '' 185 if (item.response) { 186 if (item.response.data) { 187 url = item.response.data || '' 188 } else { 189 url = item.url || '' 190 } 191 } else { 192 url = item.url || '' 193 } 194 return { name: item.name, url: url, uid: item.uid } 195 }) 196 this.fileList = attachment 197 // 回显给业务,不携带 /dispatch 前缀 198 this.$emit('change', this.fileList) 199 } 200 }, 201 202 // 图片预览 203 handlePreview(file) { 204 // 预览时要携带 /dispatch 前缀 205 this.imageUrl = this.getFileAccessHttpUrl(file.url) 206 this.previewVisible = true 207 this.currentFile = file 208 }, 209 210 // 下载 211 handleDownload(file) { 212 const link = document.createElement('a') 213 link.href = file.url 214 link.download = file.name 215 link.click() 216 URL.revokeObjectURL(link.href) 217 }, 218 219 // 删除 220 handleRemove(file) { 221 let index 222 this.fileList.find((item, idx) => { 223 if (item.uid === file.uid) { 224 index = idx 225 return 226 } 227 }) 228 if (typeof index !== 'undefined') { 229 this.fileList.splice(index, 1) 230 } 231 // 回显给业务 232 this.$emit('change', this.fileList) 233 }, 234 235 // 长按保存图片 236 down(url, file) { 237 this.time = setTimeout(() => { 238 // 这里就按照chrome等新版浏览器来处理 239 const link = document.createElement('a') 240 link.href = url 241 link.setAttribute('download', file.name) 242 link.click() 243 }, 1000) 244 }, 245 246 up() { 247 clearTimeout(this.time) 248 } 249 } 250 251 } 252 253 </script> 254 255 256 <style lang="scss" scoped> 257 .custom-box-img { 258 position: fixed; 259 z-index: 1002; 260 left: 0; 261 right: 0; 262 top: 1rem; 263 display: flex; 264 bottom: 0; 265 background-color: #ffffff; 266 align-items: center; 267 &.dark { 268 background-color: #000000; 269 .el-icon-close { 270 color: #ffffff; 271 } 272 } 273 274 .el-icon-close { 275 position: absolute; 276 z-index: 1003; 277 right: 10px; 278 top: 10px; 279 font-size: 18px; 280 color: #000000; 281 &:before { 282 font-size: 30px; 283 } 284 } 285 286 .img-con { 287 width: 100%; 288 text-align: center; 289 overflow: auto; 290 img { 291 max-width: 100%; 292 height: auto; 293 vertical-align: middle; 294 } 295 296 video { 297 vertical-align: middle; 298 } 299 } 300 301 .download-icon { 302 margin: 0 auto; 303 z-index: 1003; 304 color: #ffffff; 305 font-size: 18px; 306 margin-top: 10px; 307 ::v-deep .el-icon-download:before { 308 font-size: 20px; 309 color: #ffffff; 310 vertical-align: middle; 311 } 312 313 .el-button--primary.is-disabled { 314 background-color: #409eff; 315 border-color: #409eff; 316 } 317 318 } 319 320 .el-carousel__container { 321 height: calc(100vh - 26px); 322 } 323 324 .el-carousel__arrow { 325 background-color: rgba(31, 45, 61, 0.5); 326 line-height: 36px; 327 } 328 329 .el-carousel__indicators--outside { 330 bottom: 0; 331 line-height: 26px; 332 } 333 } 334 335 /deep/ .el-upload-list--picture-card .el-upload-list__item { 336 width: 2rem; 337 height: 2rem; 338 } 339 340 .file-container, 341 /deep/ .el-upload-list--picture-card .el-upload-list__item-thumbnail { 342 width: 100%; 343 height: 100%; 344 }
标签:el,vue,封装,url,fileList,element,item,file,return From: https://www.cnblogs.com/buluzombie/p/16768222.html