vue 文件上传通用组件

138 阅读2分钟

vue文件上传通用组件

<template>
  <div class="upload-button">
    <template v-if="multiple">
      <input
        ref="input"
        type="file"
        multiple="multiple"
        :accept="acceptType"
        @change="handleChange"
      />
    </template>
    <template v-else>
      <input
        ref="input"
        type="file"
        :accept="acceptType"
        @change="handleChange"
      />
    </template>
  </div>
</template>

<script>
import { reactive, ref } from "@vue/composition-api";
import { Message } from "element-ui";
import { post } from "axios"; // 请求也是的,建议直接使用项目中已经封装好的请求函数来调接口。我这是自己搭建的练手的项目,就没去封装请求。
import commonApi from "@/api/common"; // 这个是接口地址,根据自己需求改。
const defaultType = [
  "bmp",
  "jpg",
  "png",
  "tif",
  "gif",
  "pcx",
  "tga",
  "exif",
  "fpx",
  "svg",
  "psd",
  "cdr",
  "pcd",
  "dxf",
  "ufo",
  "eps",
  "ai",
  "raw",
  "WMF",
  "webp",
];
export default {
  props: {
    multiple: {
      // 是否多选
      type: Boolean,
      default: false,
    },
    acceptType: {
      // 文件类型
      type: String,
      default: "image/*",
    },
    type: {
      // 限制上传文件类型
      type: String,
      default: undefined,
    },
    size: {
      // 限制上传文件尺寸
      type: String,
      default: undefined,
    },
    bulk: {
      // 限制上传文件大小
      type: Number,
      default: 0,
    },
  },
  setup(props, c) {
    const { bulk, type, size, multiple } = reactive(props);
    const uploading = ref(false);
    const input = ref(null);
    const url = ref(undefined);
    let uploadFiles = reactive([]);

    const inputClick = () => {
      if (uploading.value) {
        return Message.warning("请等待前面的文件完成上传!");
      }
      return input.value.click();
    };

    const handleChange = ({ target }) => {
      if (multiple) uploadFiles = [...target.files];
      uploadFile(target.files[0]);
      target.value = "";
    };

    const uploadFile = async (file) => {
      try {
        // 限制文件类型
        if (type) await detectorType(file);
        //
        if (bulk) await detectorBulk(file);
        if (size) await detectorSize(file);
        uploading.value = true;
        const fd = new FormData();
        url.value = commonApi.addUserEmoticon;
        fd.append("file", file); // 可以通过这种形式,来传递其他项目中要传递的参数。
        const data = await post(url.value, fd, {
          headers: {
            "content-type": "multipart/form-data",
          },
        });
        c.emit("url", data); // 将请求到的数据 抛出去
        uploaded(false);
      } catch (err) {
        uploaded(err);
      }
    };
    const detectorType = (file) => {
      return new Promise((resolve, reject) => {
        const sizeList = type.split(",");
        const fileSize = file.name.split(".");
        const fileExtension = fileSize[fileSize.length - 1].toLowerCase();
        if (!sizeList.includes(fileExtension)) {
          if (!defaultType.includes(fileExtension)) {
            Message.error("文件类型不对!");
          } else {
            Message.error("图片类型不对!");
          }
          reject(new Error());
        } else {
          resolve(true);
        }
      });
    };
    const detectorBulk = (file) => {
      return new Promise((resolve, reject) => {
        const fileSize = file.size / 1024 / 1024;
        if (fileSize > bulk) {
          Message.error(`大小超出${bulk}M`);
          reject(new Error());
        } else {
          resolve(true);
        }
      });
    };

    const detectorSize = (file) => {
      return new Promise((resolve, reject) => {
        const image = new Image();
        const URL = window.URL || window.webkitURL;
        image.onload = () => {
          const sizes = size.split(",");
          if (
            image.width === Number(sizes[0]) &&
            image.height === Number(sizes[1])
          ) {
            resolve(true);
          } else {
            Message.error({
              type: "error",
              message: `请上传尺寸为 ${sizes.join(" x ")} 的图片`,
            });
            reject(new Error());
          }
        };
        image.src = URL.createObjectURL(file);
      });
    };

    const uploaded = (err, state = false) => {
      uploading.value = false;
      if (!err) {
        if (multiple && uploadFiles.length > 1) {
          uploadFiles = uploadFiles.slice(1, uploadFiles.length - 1);
          uploadFile(uploadFiles[0]);
        } else {
          Message.success("上传成功!");
        }
      }
    };

    return {
      input,
      inputClick,
      handleChange,
    };
  },
};
</script>

<style scoped lang="less"></style>

上传组件图片预览

 使用 fileReader()这个构造函数
 reader.readAsDataURL(file)
 const fr = new fileReader()
 fr.onload = function(){   
     this.imgsrc = fr.result
 }