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
        :style="buttonStyle"
        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
      },
      buttonStyle: {
     
     
       type: Object,
       default: () => ({
     
     })
     }
    },
    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.使用效果
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_39953537/article/details/100039094