vue結合element實現多圖上傳組件
簡介
多圖上傳在後臺管理系統中的表單和富文本中應用較多。這裏實現的有多圖的上傳,預覽,單個的刪除等常用功能
主要依賴說明 (先安裝,步驟略)
{
"element-ui": "2.11.1",
"vue": "^2.6.10",
"vue-router": "^3.0.1"
}
正文
1.組件
src/components/MultipleUpload.vue
<template>
<div class="upload-container">
<el-tooltip class="item" effect="dark" content="上傳圖片" placement="bottom" :hide-after="800">
<el-button icon="el-icon-upload" size="mini" type="primary" @click="showDialog">上傳圖片</el-button>
</el-tooltip>
<el-dialog title="上傳圖片" append-to-body width="700px" :visible.sync="dialogVisible" center>
<div v-for="(item,index) in imgSrcList" :key="index" class="img-box">
<span class="delete-image" title="點擊刪除">
<i class="el-icon-delete-solid" @click="deleteImage(index)" />
</span>
<img v-if="item" class="img" :src="item" alt />
</div>
<div class="uploadImg-box">
<input
ref="fileElem"
accept="image/*"
class="img-input"
type="file"
multiple="multiple"
@change="onchange"
/>
<el-button class="btn" size="small" type="primary" @click="handleOpenFile">點擊上傳</el-button>
</div>
<div class="btn-box">
<el-button @click="dialogVisible = false">取 消</el-button>
<el-button :loading="loading" type="primary" @click="handleSubmit">確 定</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import { Loading } from 'element-ui'
import { readFile } from '@/utils/upload' // 見下文
import { Base64ToBlob } from '@/utils/cos' // 見下文
// 定義的接口根據自己項目更換
import { uploadImage } from '@/api/upload'
export default {
name: 'MultipleUpload',
props: {
// 最大上傳文件的大小
maxFileSize: {
type: Number,
default: 5
}
},
data() {
return {
dialogVisible: false,
loading: false,
imgSrcList: []
}
},
methods: {
// 打開文件
handleOpenFile() {
const input = this.$refs.fileElem
// 解決同一個文件不能監聽的問題
input.addEventListener(
'click',
function() {
this.value = ''
},
false
)
// 點擊input
input.click()
},
// 顯示彈窗
showDialog() {
this.dialogVisible = true
this.imgSrcList = []
},
// 監聽input上傳
async onchange() {
try {
// 文件列表
const files = this.$refs.fileElem.files
// 文件所有尺寸
const sizes = []
// 所有文件的base64位地址
const allReadFile = []
for (let index = 0; index < files.length; index++) {
const item = files[index]
sizes.push(item.size)
allReadFile.push(readFile(item))
}
// 獲取最大尺寸檢驗
const maxSize = Math.max.apply(null, sizes)
if (maxSize > 1024 * 1024 * this.maxFileSize) {
this.$message({
message: `圖片不得大於${this.maxFileSize}M`,
type: 'warning',
duration: 2000
})
return
}
// 讀取所有文件爲base64數據
const base64List = await Promise.all(allReadFile)
this.imgSrcList = [...this.imgSrcList, ...base64List]
} catch (error) {
console.log(error)
}
},
// 確定上傳
async handleSubmit() {
if (!this.imgSrcList.length) {
this.$message({
message: '請上傳圖片!',
type: 'error'
})
return
}
// 添加頁面loading
const loadingInstance = Loading.service({
fullscreen: true,
text: '上傳中...'
})
// 添加按鈕loading
this.loading = true
try {
// 所有blob文件
const blobFiles = []
// 所有上傳圖片請求
const allRequest = []
// Base64 數據轉成blob數據
this.imgSrcList.forEach(item => {
const blobFile = Base64ToBlob(item)
blobFiles.push(blobFile)
})
// 添加請求
blobFiles.forEach(item => {
allRequest.push(uploadImage(item))
})
// 執行請求拿到結果
const urlList = await Promise.all(allRequest)
// 分發事件
this.$emit('success', urlList)
} catch (error) {
console.log(error, error)
}
// 停止loading關閉彈窗
this.loading = false
this.dialogVisible = false
loadingInstance.close()
},
// 刪除圖片
deleteImage(index) {
this.imgSrcList.splice(index, 1)
}
}
}
</script>
<style rel="stylesheet/scss" lang="scss" scoped>
.btn-box {
text-align: right !important;
}
.img-box {
position: relative;
display: inline-block;
width: 120px;
margin-right: 10px;
margin-bottom: 10px;
text-align: center;
.img {
width: 100%;
}
.delete-image {
display: none;
.el-icon-delete-solid {
width: 40px;
height: 40px;
line-height: 40px;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
font-size: 20px;
color: #000;
font-weight: 900;
}
}
&:hover {
.delete-image {
cursor: pointer;
width: 100%;
height: 100%;
position: absolute;
background-color: rgba(255, 255, 255, 0.6);
display: inline-block;
}
}
}
.uploadImg-box {
width: 100%;
height: 40px;
margin: 0 auto;
border-radius: 6px;
position: relative;
margin: 20px 0;
.img-input {
display: none;
}
.btn {
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
}
}
</style>
2.使用
<template>
<div >
<multiple-upload @success="handleImageSuccess" />
</div>
</template>
<script>
import MultipleUpload from '@/components/MultipleUpload'
export default {
name: 'AppForm',
components: {
MultipleUpload
},
methods: {
handleImageSuccess(urlList) {
console.log(urlList)
}
}
}
</script>
3.補充src/utils/upload.js 文件 readFile
方法
/**
*
* @param {file} file 源文件
* @desc 讀取圖片文件爲base64文件格式
* @retutn 返回base64文件
*/
export const readFile = file => {
return new Promise((resolve, reject) => {
const reader = new FileReader()
reader.onload = e => {
const data = e.target.result
resolve(data)
}
reader.onerror = () => {
const err = new Error('讀取圖片失敗')
reject(err.message)
}
reader.readAsDataURL(file)
})
}
4.補充src/utils/cos 文件 Base64ToBlob
方法
// base64轉換成file文件
export function Base64ToBlob(urlData) {
// 去掉url的頭,並轉換爲byte
const bytes = window.atob(urlData.split(',')[1])
// 處理異常,將ascii碼小於0的轉換爲大於0
const ab = new ArrayBuffer(bytes.length)
const ia = new Uint8Array(ab)
for (let i = 0; i < bytes.length; i++) {
ia[i] = bytes.charCodeAt(i)
}
return new Blob([ab], {
type: 'image/png'
})
}
5.使用效果