JS-Vue获取图片信息-上传

本文档展示了如何在Vue.js项目中实现图片上传并进行格式、宽高和大小的校验,以及文件唯一性校验。通过ElementUi的上传组件监听Change事件获取file对象,然后获取文件大小、MD5值和图片宽高信息。同时,提供了文件信息的封装及展示组件,用于显示文件的详细信息,并进行格式校验。示例代码包括上传文件、文件信息获取、MD5计算、图片尺寸获取等关键步骤。
摘要由CSDN通过智能技术生成

JS-Vue获取图片信息

今天产品的一个需求是要求用户上传图片时候,对格式进行校验

Demo预览 http://demo.webwlx.cn/#/ImgInfoDemo

ImgInfoDemo

具体需求

  • 获取图片信息(格式,宽高,大小)
  • 文件唯一性校验(MD5值)

实现思路

  • 上传文件,使用Element Ui 的上传组件 监听Change
  • 获取file文件的临时路径
  • 使用临时路径,获取宽高
  • 获取MD5,文件的唯一性校验

代码片段

// cnpm i SparkMD5 -S
import SparkMD5 from "spark-md5";
/* 获取文件大小 */
const getSize = (size) => {
  let data = "";
  if (size < 0.1 * 1024) {
    //如果小于0.1KB转化成B
    data = size.toFixed(2) + "B";
  } else if (size < 0.1 * 1024 * 1024) {
    //如果小于0.1MB转化成KB
    data = (size / 1024).toFixed(2) + "KB";
  } else if (size < 0.1 * 1024 * 1024 * 1024) {
    //如果小于0.1GB转化成MB
    data = (size / (1024 * 1024)).toFixed(2) + "MB";
  } else {
    //其他转化成GB
    data = (size / (1024 * 1024 * 1024)).toFixed(2) + "GB";
  }
  let sizestr = data + "";
  let len = sizestr.indexOf(".");
  let dec = sizestr.substr(len + 1, 2);
  if (dec == "00") {
    //当小数点后为00时 去掉小数部分
    return sizestr.substring(0, len) + sizestr.substr(len + 3, 2);
  }
  return sizestr;
};
/* 获取Md5 */
const getMd5 = (file) => {
  return new Promise((reslove) => {
    let fileReader = new FileReader();
    let spark = new SparkMD5.ArrayBuffer();
    // 获取文件二进制数据
    fileReader.readAsArrayBuffer(file);
    fileReader.onload = function (e) {
      spark.append(e.target.result);
      let md5 = spark.end();
      reslove(md5);
    };
  });
};
/* 获取图片宽高 */
const getImgInfo = (fileUrl) => {
  return new Promise((reslove) => {
    let img = new Image();
    img.src = fileUrl;
    img.style.display = "none";
    img.onload = () => {
      let { width, height } = img;
      reslove({ width, height });
    };
  });
};
/* 获取完成的文件信息 */
const fileInfo = async (file) => {
  let fileInfo = new Object();
  let { raw, size } = file;
  let { type: fileType } = raw;
  let fileUrl = window.URL.createObjectURL(raw);
  fileInfo.fileUrl = fileUrl; // 临时路径
  fileInfo.fileType = fileType;
  if (fileType.indexOf("image") !== -1) {
    /* 类型 图片 */
    fileInfo.type = 1;
    let { width, height } = await getImgInfo(fileUrl);
    Object.assign(fileInfo, { width, height });
  }
  fileInfo.size = size;
  fileInfo.sizeInfo = getSize(size);
  let md5 = await getMd5(raw);
  fileInfo.md5 = md5;
  return fileInfo;
};

export { fileInfo };

使用示例

<template>
  <div class="page-container">
    <div class="wid">
      <h1>读取图片信息</h1>
      <div class="upload-box">
        <div class="flex">
          <el-upload class="upload-demo" drag multiple :accept="uploadConfig.accept" :auto-upload="uploadConfig.autoUpload" :action="uploadConfig.action" :show-file-list="uploadConfig.showFileList" :on-change="fileChange">
            <i class="el-icon-upload"></i>
            <div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
            <div class="el-upload__tip" slot="tip">只能上传jpg/png文件,且不超过500kb</div>
          </el-upload>
          <div class="config-box">
            <p>
              图片大小:<span>{{ fileConfig.size }} MB</span>
            </p>
            <p>
              图片宽度:<span>{{ fileConfig.width }} px</span>
            </p>
            <p>
              图片宽度:<span>{{ fileConfig.height }} px</span>
            </p>
          </div>
        </div>

        <showFileVue v-model="fileList" />
      </div>
    </div>
  </div>
</template>

<script>
import { fileInfo } from "./getImgInfo";
import showFileVue from "./components/showFile.vue";
export default {
  name: "ImgInfoDemo",
  components: { showFileVue },
  data() {
    return {
      fileList: [],
      uploadConfig: {
        action: "", // 上传Url,
        showFileList: false,
        autoUpload: false,
        accept: "image/jpeg,image/jpg,image/gif,image/png",
      },
      fileConfig: {
        size: 10, // Mb
        width: 1920,
        height: 1080,
      },
    };
  },
  created() {},
  methods: {
    /* 选择文件回调 */
    async fileChange(file) {
      let newFile = await fileInfo(file);
      /* 判断是否上传过了 */
      let md5Arr = this.fileList.map((item) => item.md5);
      if (md5Arr.indexOf(newFile.md5) !== -1) {
        this.$message({ message: `${file.name}已经选择过了,请不要重复选择`, type: "success" });
        return false;
      }
      Object.assign(file, newFile);
      let { status, errArr } = await this.checkFile(file);
      Object.assign(file, { status, errArr });
      this.fileList.push(file);
    },
    /* 校验是否符合要求 */
    async checkFile(file) {
      let status = false; // 校验状态
      let errArr = [];
      let { width, height, size } = this.fileConfig;
      if (width !== file.width) {
        errArr.push("文件宽度错误");
      }
      if (height !== file.height) {
        errArr.push("文件高度错误");
      }
      if (file.size > size * 1024 * 1024) {
        errArr.push("文件大小超出");
      }
      status = !errArr.length;
      return { status, errArr };
    },
  },
};
</script>

<style lang="scss" scoped>
.flex {
  display: flex;
  align-items: flex-start;
  .config-box {
    margin-left: 40px;
    p {
      line-height: 2;
      span {
        color: red;
      }
    }
  }
}
</style>

封装显示组件,传入FIleList

<template>
  <div v-if="fileList.length" class="file-container">
    <el-card :body-style="{ padding: '0px 10px 10px 10px' }">
      <div>
        <el-table :data="fileList" style="width: 100%">
          <el-table-column type="index" label="序号" width="100" />
          <el-table-column prop="prop" label="素材文件" width="240" align="center">
            <template #default="{ row }">
              <div class="metrial-box">
                <div class="img-box">
                  <img :src="row.fileUrl" :alt="row.name" />
                </div>
                <p class="title text-center">{{ row.name }}</p>
              </div>
            </template>
          </el-table-column>
          <el-table-column prop="prop" label="素材信息">
            <template #default="{ row }">
              <div class="file-info-box">
                <p>分辨率:{{ row.width + "*" + row.height }}</p>
                <p>格式:{{ row.fileType }}</p>
                <p>大小:{{ row.sizeInfo }}</p>
              </div>
            </template>
          </el-table-column>
          <el-table-column prop="prop" label="格式校验">
            <template #default="{ row }">
              <div class="flex-alc status">
                <img v-if="row.status" src="https://willmid-img.oss-cn-shanghai.aliyuncs.com/2021/11/25/c9f93ac24a509e5a0b8a5715b23249b3.png" alt="" />
                <img v-else src="https://willmid-img.oss-cn-shanghai.aliyuncs.com/2021/11/25/c92383ea2fa7ccaf1917dafb77a4556a.png" alt="" />
                {{ row.status ? "校验通过" : "校验失败" }}
              </div>
              <p v-if="!row.status" class="tips">{{ row.errArr.join("-") }}</p>
            </template>
          </el-table-column>
          <el-table-column type="index" label="操作" width="100">
            <template #default="scope">
              <el-button @click="delBtn(scope.$index)" type="danger" size="mini" icon="el-icon-close">删除</el-button>
            </template>
          </el-table-column>
        </el-table>
      </div>
    </el-card>
  </div>
</template>

<script>
export default {
  name: "ShowFileList",
  props: {
    value: {
      type: Array,
      default: new Array(),
    },
  },
  data() {
    return {};
  },
  computed: {
    fileList() {
      return this.value;
    },
  },
  methods: {
    /* 删除素材 */
    delBtn(index) {
      this.fileList.splice(index, 1);
    },
  },
};
</script>

<style lang="scss" scoped>
.progress {
  padding: 20px 0;
}
:deep(.el-table th) {
  background: none !important;
  margin-bottom: 10px;
}
.tips {
  color: red;
}
.status {
  display: flex;
  align-items: center;
  img {
    margin-right: 10px;
    width: 20px;
    height: 20px;
    display: block;
  }
  .mds-chenggong {
    color: red;
  }
  .mds-shibai {
    color: green;
  }
}

.file-container {
  margin-top: 20px;
  .metrial-box {
    display: flex;
    justify-content: center;
    flex-direction: column;
    .title {
      width: 100%;
      margin-top: 10px;
    }
    .img-box {
      height: 110px;
      border-radius: 4px;
      overflow: hidden;
      img {
        display: block;
        width: 100%;
        height: 100%;
        object-fit: contain;
      }
    }
  }
}
</style>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值