vue結合element實現多圖上傳組件

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.使用效果
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章