单张图片上传组件

一、input实现文件上传

【1】type属性 

type='file' 表示文件域,用于文件上传

【2】accept属性

input框的accept属性值,它规定能够通过文件上传进行提交的文件类型 eg:  accept="image/gif, image/jpeg"

【3】实例

<input type="file" name="file" accept="image/png,image/jpg,image/gif,image/JPEG" />

// 上面代码意思是:input元素类型为文件域; accept属性表示可上传提交的文件类型为 image/png,image/jpg,image/gif,image/JPEG

二、封装上传文件的工具函数

新建一个getFile.js文件,通过创建type为file类型的input框实现文件上传功能

export default function ({
  accept = "", // input框的accept属性值,它规定能够通过文件上传进行提交的文件类型 eg:  accept="image/gif, image/jpeg"
  multiple = false, // 是否多个
  exts = [], // 文件格式
  maxSize = 0 // 文件大小
}) {
  exts = exts.map(it => it.toLowerCase());
  return new Promise((resolve, reject) => {
    let input = document.createElement("input");
    input.setAttribute("type", "file");
    input.setAttribute("style", "position:absolute;left: -1000px;");
    accept && input.setAttribute("accept", accept);
    multiple && input.setAttribute("multiple", "multiple");
    document.body.appendChild(input);
    input.focus();
    input.click();
    input.addEventListener("change", function () {
      let fileExts = Array.from(this.files)
        .map(it => it.name.replace(/.*\.([^.]+)$/, "$1"))
        .map(it => it.toLowerCase());

      if (fileExts.some(it => !exts.includes(it))) {
        reject(`只支持文件格式:${exts.join(",")}`);
      }

      if (maxSize > 0) {
        if (Array.from(this.files).some(it => it.size / 1024 / 1024 > maxSize)) {
          reject(`最大文件大小${maxSize}M`);
        }
      }

      if (multiple) {
        resolve(this.files);
      } else {
        resolve(this.files[0] || null);
      }
      input.parentElement.removeChild(input);
    })

  })
}

三、上传文件组件

新建一个imageSelector.vue文件,实现可复用的上传文件组件

<template>
  <div @click="onClick" class="imageSelector" :class="className">
    <img class="imageSelector-img" v-if="src" :src="src" />
    <slot v-else />
  </div>
</template>
<script>
import getFile from "@/libs/getFile";
export default {
  props: {
    value: {
      type: String,
    },
    disabled: {
      type: Boolean,
      default: false,
    },
  },
  data() {
    return {
      src: this.value,
      imgFile: "",
    };
  },
  watch: {
    src(val) {
      this.$emit("input", val);
      this.$emit("getimgFile", this.imgFile);
    },
    value(val) {
      this.src = val;
      this.imgFile = "";
    },
  },
  computed: {
    className() {
      return {
        "imageSelector-disabled": this.disabled,
        "imageSelector-noImg": !this.src,
      };
    },
  },
  methods: {
    onClick() {
      if (this.disabled) return;
      this.getFile();
    },
    async getFile() {
      try {
        let image = await getFile({
          accept: "image/jpeg,image/png",
          exts: ["jpg", "png"],
          maxSize: 10,
        });
        console.log(image);

        if (image) {
          this.imgFile = image;
          this.src = await this.fileToBase64(image);
        }
      } catch (e) {
        this.$Message.error(e);
      }
    },
    fileToBase64(file) {
      return new Promise((resolve, reject) => {
        if (!file) reject(new Error("no file"));
        let reader = new FileReader();
        reader.addEventListener("load", () => {
          resolve(reader.result);
        });
        reader.readAsDataURL(file);
      });
    },
  },
};
</script>
<style scoped>
.imageSelector {
  display: inline-block;
  border: 1px solid #dcdee2;
  border-radius: 4px;
  overflow: hidden;
  cursor: pointer;
}
.imageSelector-disabled {
  cursor: default;
}
.imageSelector-noImg {
  height: 50px;
  width: 50px;
}
.imageSelector-img {
  width: 100%;
  height: 100%;
  vertical-align: middle;
}
</style>

四、页面调用

【1】引入

import ImageSelector from "./imageSelector.vue";
export default {
  components: { ImageSelector },
}

【2】使用

<ImageSelector
  ref="photo"
  class="photo"
  @getimgFile="getimgFile" // 上传之后处理逻辑
  v-model="params.file" // 双向绑定值
  @click="uploadPhoto"  // 上传之前处理逻辑
/>

【3】处理逻辑

  methods: {
    uploadPhoto() {
      this.imgFile = [];
    },
    getimgFile(val) {
      this.imgFile = [];
      if (val) {
        this.imgFile.push(val);
      }
    },
  }

五、效果展示 

文章每周持续更新,可以微信搜索「 前端大集锦 」第一时间阅读,回复【视频】【书籍】领取200G视频资料和30本PDF书籍资料

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

@Demi

您的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值