<template> <div class="component-upload-image"> <ul class="el-upload-list el-upload-list--picture-card"> <li tabindex="0" class="el-upload-list__item is-success" v-for="(item, index) in fileList" :key="index"> <video v-if="item.url.substr(-4) == '.mp4'" :src="item.url"></video> <img v-else :src="item.url" :alt="item.name" class="el-upload-list__item-thumbnail" /> <!-- <a class="el-upload-list__item-name"> <i class="el-icon-document"></i> </a> --> <label class="el-upload-list__item-status-label"> <i class="el-icon-upload-success el-icon-check"></i> </label> <!-- <i class="el-icon-close"></i> <i class="el-icon-close-tip">按 delete 键可删除</i> --> <span class="el-upload-list__item-actions"> <span class="el-upload-list__item-preview" @click="handlePictureCardPreview(item)"> <i class="el-icon-zoom-in"></i> </span> <span class="el-upload-list__item-delete" @click="handleRemove(item)" v-if="isShowEditButton"> <i class="el-icon-delete"></i> </span> </span> </li> </ul> <el-upload v-if="isShowEditButton" multiple :action="uploadImgUrl" list-type="picture-card" :on-success="handleUploadSuccess" :before-upload="handleBeforeUpload" :limit="limit" :on-error="handleUploadError" :on-exceed="handleExceed" name="file" :on-remove="handleRemove" :show-file-list="false" :headers="headers" :file-list="fileList" :on-preview="handlePictureCardPreview" :class="{ hide: this.fileList.length >= this.limit }"> <i class="el-icon-plus"></i> </el-upload> <!-- 上传提示 --> <div class="el-upload__tip" slot="tip" v-if="showTip"> {{ $t("请上传") }} <template v-if="fileSize"> {{ $t("大小不超过") }} <b style="color: #f56c6c">{{ fileSize }}MB</b> </template> <template v-if="fileType"> {{ $t("格式为") }} <b style="color: #f56c6c">{{ fileType.join("/") }}</b> </template> {{ $t("的文件") }} </div> <el-dialog :visible.sync="dialogVisible" :title="$t('预览')" width="800" append-to-body> <template v-if="dialogImageUrl"> <video v-if="dialogImageUrl.substr(-4) == '.mp4'" :src="dialogImageUrl" controls autoplay style="display: block; max-width: 100%; margin: 0 auto"></video> <img v-else :src="dialogImageUrl" style="display: block; max-width: 100%; margin: 0 auto" /> </template> </el-dialog> </div> </template> <script> import { getToken } from "@/utils/auth" export default { props: { value: [String, Object, Array], // 图片数量限制 limit: { type: Number, default: 5 }, // 大小限制(MB) fileSize: { type: Number, default: 5 }, // 文件类型, 例如['png', 'jpg', 'jpeg'] fileType: { type: Array, default: () => ["png", "jpg", "jpeg", "mp4"] }, // 是否显示提示 isShowTip: { type: Boolean, default: true }, //是否显示编辑按钮 isShowEditButton: { type: Boolean, default: true } }, data() { return { number: 0, uploadList: [], dialogImageUrl: "", dialogVisible: false, hideUpload: false, baseUrl: process.env.VUE_APP_BASE_API, uploadImgUrl: process.env.VUE_APP_BASE_API + "/app-api/file/upload", // 上传的图片服务器地址 headers: { Authorization: "Bearer " + getToken() }, fileList: [] } }, watch: { value: { handler(val) { if (val) { // 首先将值转为数组 const list = Array.isArray(val) ? val : this.value.split(",") // 然后将数组转为对象数组 this.fileList = list.map((item) => { if (typeof item === "string") { if (item.indexOf(this.baseUrl) === -1) { item = { name: item, url: item } } else { item = { name: item, url: item } } } return item }) } else { this.fileList = [] return [] } }, deep: true, immediate: true } }, computed: { // 是否显示提示 showTip() { return this.isShowTip && (this.fileType || this.fileSize) } }, methods: { // 删除图片 handleRemove(file, fileList) { const findex = this.fileList.map((f) => f.name).indexOf(file.name) if (findex > -1) { this.fileList.splice(findex, 1) this.$emit("input", this.listToString(this.fileList)) } }, // 上传成功回调 handleUploadSuccess(res) { console.log({ res }) this.uploadList.push({ name: res.data.split("/").pop(), url: res.data }) if (this.uploadList.length === this.number) { this.fileList = this.fileList.concat(this.uploadList) this.uploadList = [] this.number = 0 this.$emit("input", this.listToString(this.fileList)) this.$modal.closeLoading() } }, // 上传前loading加载 handleBeforeUpload(file) { let isImg = false if (this.fileType.length) { let fileExtension = "" if (file.name.lastIndexOf(".") > -1) { fileExtension = file.name.slice(file.name.lastIndexOf(".") + 1) } isImg = this.fileType.some((type) => { if (file.type.indexOf(type) > -1) return true if (fileExtension && fileExtension.indexOf(type) > -1) return true return false }) } else { isImg = file.type.indexOf("image") > -1 } if (!isImg) { this.$modal.msgError(`文件格式不正确, 请上传${this.fileType.join("/")}图片格式文件!`) return false } if (this.fileSize) { const isLt = file.size / 1024 / 1024 < this.fileSize if (!isLt) { this.$modal.msgError(`上传头像图片大小不能超过 ${this.fileSize} MB!`) return false } } this.$modal.loading("正在上传图片,请稍候...") this.number++ }, // 文件个数超出 handleExceed() { this.$modal.msgError(`上传文件数量不能超过 ${this.limit} 个!`) }, // 上传失败 handleUploadError() { this.$modal.msgError("上传图片失败,请重试") this.$modal.closeLoading() }, // 预览 handlePictureCardPreview(file) { this.dialogImageUrl = file.url this.dialogVisible = true // window.open(file.url) }, // 对象转成指定字符串分隔 listToString(list, separator) { let strs = "" separator = separator || "," for (let i in list) { strs += list[i].url.replace(this.baseUrl, "") + separator } return strs != "" ? strs.substr(0, strs.length - 1) : "" } } } </script> <style scoped lang="scss"> // .el-upload--picture-card 控制加号部分 ::v-deep.hide .el-upload--picture-card { display: none; } // 去掉动画效果 ::v-deep .el-list-enter-active, ::v-deep .el-list-leave-active { transition: all 0s; } ::v-deep .el-list-enter, .el-list-leave-active { opacity: 0; transform: translateY(0); } .component-upload-image { display: flex; flex-wrap: wrap; } </style>