一、代碼實現(xiàn)(具體配置文檔)
1. 默認圖片上傳
- 適用于:文件上傳接口只要求file二進制文件,無需其他參數(shù)。(或者配置data屬性用于上傳時附帶的額外參數(shù))。
- 該實現(xiàn)方式會在選擇完圖片后就根據(jù)配置好的action的接口上傳地址自動上傳圖片。
- 重點就是配置好action屬性,以及限制類型和大小。
<template>
<div class="component-box">
<!-- list-type :文件列表的類型,text/picture/picture-card -->
<!-- name 上傳的文件字段名 string — file -->
<!-- show-file-list 是否顯示已上傳文件列表 -->
<!-- this.fileList.length >= this.limit 控制加號部分,不可以再加 -->
<!-- disabled 是否禁用 boolean — false -->
<el-upload
:action="uploadImgUrl"
list-type="picture-card"
:on-success="handleSuccess"
:before-upload="handleBefore"
:limit="limit"
:on-error="handleError"
:on-exceed="handleExceed"
name="files"
:on-remove="handleRemove"
:show-file-list="true"
:headers="headers"
:file-list="fileList"
:on-preview="handlePreview"
:class="{ hide: this.fileList.length >= this.limit }"
:disabled="disabled"
:data="uploadData"
>
<i class="el-icon-plus" />
</el-upload>
<!-- 上傳提示 -->
<div v-if="showTip" slot="tip" class="el-upload__tip">
請上傳
<template v-if="fileSize">
大小不超過 <b style="color: #f56c6c">{{ fileSize }}MB</b>
</template>
<template v-if="fileType">
格式為 <b style="color: #f56c6c">{{ fileType.join('/') }}</b>
</template>
的文件
</div>
<el-dialog
:close-on-click-modal="false"
:close-on-press-escape="false"
:visible.sync="isVisible"
title="預(yù)覽"
width="800"
append-to-body
>
<img :src="dialogImageUrl" style="display: block; max-width: 100%; margin: 0 auto" />
</el-dialog>
</div>
</template>
<script>
//獲取實際項目的token
// import { getToken } from '@/utils/auth'
export default {
props: {
// 選擇的圖片數(shù)據(jù)
value: [String, Object, Array],
// 圖片數(shù)量限制 limit 最大允許上傳個數(shù)
limit: {
type: Number,
default: 10
},
// 大小限制(MB)
fileSize: {
type: Number,
default: 5
},
// 文件類型, 例如['png', 'jpg', 'jpeg']
fileType: {
type: Array,
default: () => ['png', 'jpg', 'jpeg']
},
// 是否顯示提示
isShowTip: {
type: Boolean,
default: true
},
// 是否禁用
disabled: {
type: Boolean,
default: false
}
},
data() {
return {
// 預(yù)覽圖片地址
dialogImageUrl: '',
// 預(yù)覽彈框是否顯示
isVisible: false,
// hideUpload: false,
// 接口地址
baseUrl: process.env.VUE_APP_BASE_API,
// 必選參數(shù),上傳的地址
uploadImgUrl: process.env.VUE_APP_BASE_API + '圖片服務(wù)器地址', // 上傳的圖片服務(wù)器地址
// headers 設(shè)置上傳的請求頭部
headers: { //獲取實際token后,取消掉注釋
// Authorization: 'Bearer ' + getToken()
},
// file-list 上傳的文件列表, 例如: [{name: 'food.jpg', url: 'https://xxx.cdn.com/xxx.jpg'}] array — []
fileList: [],
// 上傳時附帶的額外參數(shù)
uploadData: { toPdf: false },
}
},
computed: {
// 是否顯示提示
showTip() {
return this.isShowTip && (this.fileType || this.fileSize)
}
},
watch: {
value: {
handler(val) {
// console.log(val,'chak')
if (val) {
// 1.將值轉(zhuǎn)為數(shù)組
const list = Array.isArray(val) ? val : this.value.split(',')
console.log(list)
// 2.然后將數(shù)組轉(zhuǎn)為對象數(shù)組
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
}
},
methods: {
// 刪除圖片
// on-remove 文件列表移除文件時的鉤子 function(file, fileList)
handleRemove(file) {
const findex = this.fileList.map(f => f.name).indexOf(file.name)
this.fileList.splice(findex, 1)
// 獲取到由所有文件的url地址組成的逗號分割的字符串
this.$emit('input', this.getString(this.fileList))
// 獲取到選擇的所有文件的所有信息
this.$emit('getInput', JSON.stringify(this.fileList))
},
// 上傳成功回調(diào)
// 文件上傳成功時的鉤子 function(response, file, fileList)
handleSuccess(res) {
if (res && res.data && res.data[0]) {
const result = res.data[0]
this.fileList.push({
name: result.originalName,
url: result.fileUrl,
id: result.id
})
// 獲取到由所有文件的url地址組成的逗號分割的字符串
this.$emit('input', this.getString(this.fileList))
// 獲取到選擇的所有文件的所有信息
this.$emit('getInput', JSON.stringify(this.fileList))
console.log(this.getString(this.fileList), 'res')
console.log(JSON.stringify(this.fileList), 'res')
}
this.loading.close()
},
// 上傳前l(fā)oading加載
// before-upload上傳文件之前的鉤子,參數(shù)為上傳的文件,
// 若返回 false 或者返回 Promise 且被 reject,則停止上傳。 function(file)
handleBefore(file) {
console.log(file, 'handleBefore')
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 => {
// 如果上傳文件的類型type是規(guī)定的類型fileType中的某一個,返回true
if (file.type.indexOf(type) > -1) return true
// 如果上傳文件的后綴是規(guī)定的類型fileType中的某一個,返回true
if (fileExtension && fileExtension.indexOf(type) > -1) return true
// 后綴返回false
return false
})
} else {
// 判斷上傳的文件的類型是否是圖片
isImg = file.type.indexOf('image') > -1
}
// 如果不是圖片則提示一下,且不可以上傳
if (!isImg) {
this.$message.error(`文件格式不正確, 請上傳${this.fileType.join('/')}圖片格式文件!`)
return false
}
// 判斷大小,B<KB<MB<GB,且1 kB = 1024 B ,1 MB = 1024 kB ,1 GB = 1024 MB。
// file.size 的單位是B
// bit就是位,也叫比特位,是計算機表示數(shù)據(jù)最小的單位 ; byte就是字節(jié)
// 1byte=8bit ; 1byte就是1B
if (this.fileSize) {
const isLt = file.size / 1024 / 1024 < this.fileSize
if (!isLt) {
this.$message.error(`上傳頭像圖片大小不能超過 ${this.fileSize} MB!`)
return false
}
}
this.loading = this.$loading({
lock: true,
text: '上傳中',
background: 'rgba(0, 0, 0, 0.7)'
})
},
// 文件個數(shù)超出
// on-exceed 文件超出個數(shù)限制時的鉤子 function(files, fileList)
handleExceed() {
this.$message.error(`上傳文件數(shù)量不能超過 ${this.limit} 個!`)
},
// 上傳失敗
// on-error 文件上傳失敗時的鉤子 function(err, file, fileList)
handleError() {
this.$message({
type: 'error',
message: '上傳失敗'
})
this.loading.close()
},
// 預(yù)覽
// on-preview 點擊文件列表中已上傳的文件時的鉤子 function(file)
handlePreview(file) {
this.dialogImageUrl = file.url
this.isVisible = true
},
// 對象轉(zhuǎn)成指定字符串分隔 (比如獲取到由所有文件的url地址組成的逗號分割的字符串)
getString(list, separator) {
let strs = ''
separator = separator || ','
for (const i in list) {
strs += list[i].url + separator
}
return strs != '' ? strs.substr(0, strs.length - 1) : ''
}
}
}
</script>
<style scoped>
/* .el-upload--picture-card 控制加號部分 */
/deep/ .hide .el-upload--picture-card {
display: none;
}
/* 去掉動畫效果 */
/deep/ .el-list-enter-active,
/deep/ .el-list-leave-active {
transition: all 0s;
}
/deep/ .el-list-enter,
.el-list-leave-active {
opacity: 0;
transform: translateY(0);
}
</style>
2. 自定義圖片上傳
- 不需要配置action,使用http-request 覆蓋默認的上傳行為,可以自定義上傳的實現(xiàn)。適用于文件上傳需要file文件和其他參數(shù)。
- 或者在http-request的方法中不做任何操作,在before-upload上傳前的校驗中,保存將要上傳的文件file,然后頁面根據(jù)實際需要,調(diào)用方法上傳圖片。(如在頁面中加一個提交按鈕,點擊調(diào)用提交方法上傳圖片)。
- 重點簡單了解FormData的使用和Content-Type的類型
// 可以根據(jù)后臺接口要求來決定參數(shù)的類型
onChange() {
//通常文件上傳是要用 FormData 格式的
this.formdata = new FormData()
this.formdata.append('file', this.file)
this.formdata.append('name', this.name)
},
// this.formdata 就是要傳給后臺的參數(shù)了
- multipart/form-data支持文件上傳的格式,一般需要上傳文件的表單則用該類型。
// 頭像上傳
// export function uploadAvatar(data) {
// return request({
// url: '/manager/user/uploadAvatar',
// method: 'post',
// data: data,
// headers: {
// 'Content-Type': 'multipart/form-data'
// }
// })
// }
<template>
<div class="component-box">
<!-- http-request 覆蓋默認的上傳行為,可以自定義上傳的實現(xiàn) -->
<el-upload
action=""
list-type="picture-card"
:before-upload="handleBefore"
:limit="limit"
:http-request="handleFileUpload"
:on-error="handleError"
:on-exceed="handleExceed"
:on-remove="handleRemove"
:show-file-list="true"
:file-list="fileList"
:on-preview="handlePreview"
:class="{ hide: fileList.length >= limit }"
:disabled="disabled"
>
<i class="el-icon-plus" />
</el-upload>
<!-- 上傳提示 -->
<div v-if="showTip" slot="tip" class="el-upload__tip">
請上傳
<template v-if="fileSize">
大小不超過 <b style="color: #f56c6c">{{ fileSize }}MB</b>
</template>
<template v-if="fileType">
格式為 <b style="color: #f56c6c">{{ fileType.join("/") }}</b>
</template>
的文件
</div>
<el-dialog
:close-on-click-modal="false"
:close-on-press-escape="false"
:visible.sync="dialogVisible"
title="預(yù)覽"
width="800"
append-to-body
>
<img
:src="isVisible"
style="display: block; max-width: 100%; margin: 0 auto"
/>
</el-dialog>
</div>
</template>
<script>
export default {
props: {
value: [String, Object, Array],
// 圖片數(shù)量限制
limit: {
type: Number,
default: 10,
},
// 大小限制(MB)
fileSize: {
type: Number,
default: 10,
},
// 文件類型, 例如['png', 'jpg', 'jpeg']
fileType: {
type: Array,
default: () => ["png", "jpg", "jpeg"],
},
// 是否顯示提示
isShowTip: {
type: Boolean,
default: true,
},
// 是否禁用
disabled: {
type: Boolean,
default: false,
},
// 詳情id
peopleId: {
type: String,
default: () => "",
},
},
data() {
return {
isVisible: "",
dialogVisible: false,
baseUrl: process.env.VUE_APP_BASE_API,
fileList: [],
// file:null,
};
},
computed: {
// 是否顯示提示
showTip() {
return this.isShowTip && (this.fileType || this.fileSize);
},
},
watch: {
value: {
handler(val) {
if (val) {
// 1.將值轉(zhuǎn)為數(shù)組
const list = Array.isArray(val) ? val : this.value.split(",");
// 2.將數(shù)組轉(zhuǎn)為對象數(shù)組
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,
},
},
methods: {
// 刪除圖片
handleRemove(file) {
const findex = this.fileList.map((f) => f.name).indexOf(file.name);
this.fileList.splice(findex, 1);
this.$emit("input", this.getString(this.fileList));
this.$emit("getInput", JSON.stringify(this.fileList));
},
// 上傳成功回調(diào)
handleUploadSuccess(res) {
console.log(res, "success");
const result = res.data[0];
this.fileList.push({
name: result.originalName,
url: result.fileUrl,
id: result.id,
});
this.$emit("input", this.getString(this.fileList));
this.$emit("getInput", JSON.stringify(this.fileList));
console.log(this.getString(this.fileList), "res");
console.log(JSON.stringify(this.fileList), "res");
this.loading.close();
},
// 上傳前l(fā)oading加載
handleBefore(file) {
// this.file = 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.$message.error(
`文件格式不正確, 請上傳${this.fileType.join("/")}圖片格式文件!`
);
return false;
}
if (this.fileSize) {
const isLt = file.size / 1024 / 1024 < this.fileSize;
if (!isLt) {
this.$message.error(`上傳頭像圖片大小不能超過 ${this.fileSize} MB!`);
return false;
}
}
this.loading = this.$loading({
lock: true,
text: "上傳中",
background: "rgba(0, 0, 0, 0.7)",
});
},
// 文件個數(shù)超出
handleExceed() {
this.$message.error(`上傳文件數(shù)量不能超過 ${this.limit} 個!`);
},
// 上傳失敗
handleError() {
this.$message({
type: "error",
message: "上傳失敗",
});
this.loading.close();
},
// 預(yù)覽
handlePreview(file) {
this.isVisible = file.url;
this.dialogVisible = true;
},
// 對象轉(zhuǎn)成指定字符串分隔
getString(list, separator) {
let strs = "";
separator = separator || ",";
for (const i in list) {
strs += list[i].url + separator;
}
return strs != "" ? strs.substr(0, strs.length - 1) : "";
},
// http-request 覆蓋默認的上傳行為,可以自定義上傳的實現(xiàn) function
// 上傳文件的文件流是無法被序列化并傳遞的。所以我們就可以使用到formdata對象,就可以輕松進行文件上傳了。
// 創(chuàng)建formdata對象實例的方式 :new FormData()
// 添加數(shù)據(jù):append(key,value) 如果key不存在會新增一條數(shù)據(jù),如果key存在,則添加到數(shù)據(jù)末尾
handleFileUpload(e) {
console.log(e);
// let _this = this
let formdata = new FormData();
formdata.append("file", e.file);
console.log(formdata, "formdata");
// 上傳圖片
// uploadAvatar(formdata)
// .then(res => {
// console.log(res,'res')
// ......
// _this.loading.close()
// })
// .catch(() => {
// _this.fileList = []
// this.loading.close()
// })
},
// 上傳圖片 (也可以在頁面上面加一個提交的按鈕,點擊按鈕調(diào)用這個方法進行上傳,上述handleFileUpload方法中不寫任何代碼)
uploadImg() {
// let formData = new FormData();
// name上傳的文件字段名上傳的文件字段名,默認是"file",具體根據(jù)接口來
// this.files 在上傳前的handleBefore方法中保存這個文件
// formData.append("file", this.files);
// uploadAvatar(formData).then((response) => {
// ......................
// });
},
},
};
</script>
<style scoped>
/* .el-upload--picture-card 控制加號部分 */
/deep/ .hide .el-upload--picture-card {
display: none;
}
/* 去掉動畫效果 */
/deep/ .el-list-enter-active,
/deep/ .el-list-leave-active {
transition: all 0s;
}
/deep/ .el-list-enter,
.el-list-leave-active {
opacity: 0;
transform: translateY(0);
}
</style>
3. 默認文件上傳
- 和上述圖片上傳是一樣的原理,只不過是限制的類型不一樣。
<template>
<div class="upload-file">
<!-- drag 是否啟用拖拽上傳 boolean — false -->
<!-- data 上傳時附帶的額外參數(shù) object -->
<el-upload :drag="drag" ref="upload" :action="uploadFileUrl" v-if="showDing" :before-upload="handleBefore"
:file-list="fileList" :limit="limit" name="files" :on-error="handleError" :on-exceed="handleExceed"
:on-success="handleSuccess" :show-file-list="false" :headers="headers" class="upload-file-uploader"
:data="uploadData">
<!-- 上傳按鈕 -->
<el-button v-if="showDing" size="mini" type="primary">選取文件</el-button>
<!-- 上傳提示 -->
<div v-if="showTip" slot="tip" class="el-upload__tip">
請上傳
<template v-if="fileSize">
大小不超過 <b style="color: #f56c6c">{{ fileSize }}MB</b>
</template>
<template v-if="fileType">
格式為 <b style="color: #f56c6c">{{ fileType.join("/") }}</b>
</template>
的文件
</div>
</el-upload>
<!-- 文件列表 -->
<transition-group class="transition-box" tag="ol">
<li v-for="(file, index) in fileList" :key="index" class="upload-item-box">
<div class="upload-item">
<div>
<el-link>
<span class="el-icon-document" style="margin-left: 10px">
{{ file.name }}
</span>
</el-link>
</div>
<div>
<el-link :underline="false" class="look" type="primary" @click="handlePrew(file)">
<span class="el-icon-view"> 查看 </span>
</el-link>
<div class="delBox" v-if="showDing">
<el-link v-if="index > number - 1" class="el-icon-delete link" :underline="false" type="danger"
@click="handleDelete(index)">刪除</el-link>
</div>
</div>
</div>
</li>
</transition-group>
</div>
</template>
<script>
// import { getToken } from "@/utils/auth";
export default {
name: "FileUpload",
props: {
// 值
value: [String, Object, Array],
// 數(shù)量限制
limit: {
type: Number,
default: 5,
},
// 大小限制(MB)
fileSize: {
type: Number,
default: 10,
},
number: {
type: Number,
default: -1000,
},
// 文件類型, 例如['png', 'jpg', 'jpeg']
fileType: {
type: Array,
default: () => ["png", "jpg", "jpeg", "doc", "xls", "ppt", "pdf"],
},
imageType: {
type: Array,
default: () => ["png", "jpg", "jpeg"],
},
// 是否顯示提示上傳提示
isShowTip: {
type: Boolean,
default: true,
},
showDing: {
type: Boolean,
default: true,
},
drag: {
type: Boolean,
default: false,
},
},
data() {
return {
loading: {},
uploadData: { toPdf: false },
baseUrl: process.env.VUE_APP_BASE_API,
uploadFileUrl: process.env.VUE_APP_BASE_API + "圖片服務(wù)器地址", // 上傳的圖片服務(wù)器地址
headers: {
// Authorization: "Bearer " + getToken(),
},
fileList: [],
files: [],
};
},
computed: {
// 是否顯示提示
showTip() {
return this.isShowTip && (this.fileType || this.fileSize);
},
},
watch: {
value: {
handler(val) {
if (val) {
this.files = val;
var that = this;
let temp = 1;
// 1.將值轉(zhuǎn)為數(shù)組
// this.fileList
const list = Array.isArray(val) ? val : this.value.split(",");
// 2.將數(shù)組轉(zhuǎn)為對象數(shù)組
this.fileList = list.map((item, index) => {
if (typeof item === "string") {
item = { url: item };
}
item.name = that.files[index].originalName;
item.uid = item.uid || new Date().getTime() + temp++;
return item;
});
} else {
this.fileList = [];
this.files = [];
return [];
}
},
deep: true,
immediate: true,
},
},
methods: {
// 預(yù)覽
handlePrew(file) {
window.open(file.fileUrl);
},
// 上傳前校檢格式和大小
handleBefore(file) {
// 校檢文件類型
if (this.fileType) {
let fileExtension = "";
if (file.name.lastIndexOf(".") > -1) {
fileExtension = file.name.slice(file.name.lastIndexOf(".") + 1);
}
// fileExtension: jfif
const isTypeOk = this.fileType.some((type) => {
// 這里注意jfif圖片 類型的解析 會在第一步直接解析成image/jpeg
if (file.type.indexOf(type) > -1) return true;
if (fileExtension && fileExtension.indexOf(type) > -1) return true;
return false;
});
if (!isTypeOk) {
this.$message.error(
`文件格式不正確, 請上傳${this.fileType.join("/")}格式文件!`
);
return false;
}
// 判斷一下,如果類型是this.imageType中的某一個,比如這里指的是圖片類型,不需要轉(zhuǎn)為pdf格式
// this.uploadData.toPdf 這個是額外的數(shù)據(jù),具體看實際項目以及和后端配合有關(guān)
if (this.imageType) {
let toPdf = true;
this.imageType.some((type) => {
// 這里注意jfif圖片 類型的解析 會在第一步直接解析成image/jpeg
if (file.type.indexOf(type) > -1) {
toPdf = false;
}
if (fileExtension && fileExtension.indexOf(type) > -1) {
toPdf = false;
}
});
this.uploadData.toPdf = toPdf;
}
}
// 校檢文件大小
if (this.fileSize) {
const isLt = file.size / 1024 / 1024 < this.fileSize;
if (!isLt) {
this.$message.error(`上傳文件大小不能超過 ${this.fileSize} MB!`);
return false;
}
}
this.loading = this.$loading({
lock: true,
text: "上傳中",
background: "rgba(0, 0, 0, 0.7)",
});
console.log(file, "file");
return true;
},
// 文件個數(shù)超出
handleExceed() {
this.$message.error(`上傳文件數(shù)量不能超過 ${this.limit} 個!`);
},
// 上傳失敗
handleError() {
console.log("handleError");
this.$message.error("上傳失敗, 請重試");
this.loading.close();
},
// 上傳成功回調(diào)
handleSuccess(res, file) {
console.log("handleSuccess", res, file);
if (res.data && res.data[0]) {
const result = res.data[0];
this.fileList.push({ id: result.id, name: result.originalName, url: result.fileUrl });
this.files.push(result);
this.$emit("getInput", this.fileList);
this.$emit("input", this.files);
// 獲取由選擇文件的id組成的以逗號分割的字符串
this.$emit("getId", this.getString(this.fileList, ',', 'id'));
this.loading.close();
} else {
this.$message.error(res.msg);
this.loading.close();
}
},
// 刪除文件
handleDelete(index) {
this.fileList.splice(index, 1);
this.files.splice(index, 1);
this.$emit("getInput", this.fileList);
this.$emit("input", this.files);
this.$emit("getId", this.getString(this.fileList, ',', 'id'));
},
// 對象轉(zhuǎn)成指定字符串分隔
getString(list, separator, FieldName) {
let strs = "";
separator = separator || ",";
for (const i in list) {
strs += list[i][FieldName] + separator;
}
return strs != "" ? strs.substr(0, strs.length - 1) : "";
},
},
};
</script>
<style scoped>
.upload-file-uploader {
margin-bottom: 5px;
}
.transition-box .upload-item-box{
border: 1px solid #e4e7ed;
line-height: 3;
margin-bottom: 10px;
position: relative;
}
.upload-item{
width: 95%;
display: flex;
justify-content: space-between;
}
.delBox{
display: inline-block;
}
.look {
margin-left: 10px;
margin-right: 10px;
}
</style>
二、效果圖
文章來源地址http://www.zghlxwxcb.cn/news/detail-809966.html
文章來源:http://www.zghlxwxcb.cn/news/detail-809966.html
到了這里,關(guān)于Element中Upload組件上傳(圖片和文件的默認上傳以及自定義上傳)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!