用vue开发一个图片上传功能

工作中遇到的需求 和大家分享下

  • 以下代码完成图片上传
  • 实线点击预览和删除图片

效果图

图片上传
图片预览删除

该组件上传图片的大致思路

1.利用H5的FileReader对象将上传的图片转成base64格式
2.利用canvas的drawImage方法重绘上传的图片
3.在利用canvas的toDataURL方法将图片压缩
4.将base64文件传递给后台(此项根据自己的项目需求来抉择,我的项目需求就是base64,所以我没有转成blob对象)

文件上传代码

1.使用input标签来获取图片文件

<form ref="uploadForm" id="uploadForm" style="display:inline;">
      <input
        type="file"
        id="fileId"
        ref="addPicFile"
        name="file"
        accept="image/jpg,image/jpeg,image/png,image/bmp"
        style="display:none;"
        @change="addPic"
      />
</form>

2.因为原生的按钮不满足我们需求,所以我们需要手动来做一个添加按钮

 <!-- 项目需求最多不能超过5个图片,所以如果图片有5个我会自动隐藏按钮  -->
<img
      class="addimg-items addBtn"
      v-show="photoList.length < 5"
      src="@/assets/img/添加图片.png"
      @click="$refs.addPicFile.click()"
/>

3.上传图片js

//添加图片
    addPic() {
      // common的upload和compress方法是我自己写得js 我会在下面贴出代码
      let file = common.upload(this.$refs.addPicFile);
      let reader = new FileReader();
      reader.onload = e => {
        let img = new Image();
        img.src = e.target.result;
        img.onload = () => {
          let imgsrc = common.compress(img);
          this.$options.methods.uploadPic.bind(this)(imgsrc);
          // 添加完成之后降input的值清空,如果不清空则会出现无法上传同一个图片的bug
          this.$refs.addPicFile.value = "";
        };
      };
      reader.readAsDataURL(file);
    },
    uploadPic(data) {
      // HTTP是我自己封装的axios的调用代码
      let res = Http.getAxios("POST", `/image/upload`, data);
      res.then(data => {
        // 因为我需要鼠标悬浮图片显示预览和删除按钮, 所以需要imgHover参数
        this.list.push({
          src: data.message,
          imgHover: false
        });
        this.$emit("addPic", this.list);
      });
    }

4.common.js

  //图片压缩
  compress(img) {
    var canvas = document.createElement("canvas");
    var ctx = canvas.getContext("2d");
    var width = img.width;
    var height = img.height;
    canvas.width = width;
    canvas.height = height;
    ctx.drawImage(img, 0, 0, width, height);
    var type = "image/jpeg";
    var img64 = canvas.toDataURL(type, 0.3);
    return img64;
  }

  //图片上传
  upload(img) {
    //判断是否支持FileReader
    if (!window.FileReader) {
      this.$Modal.warning({
        title: "警告",
        content: "您的设备不支持图片预览功能,如需该功能请升级您的设备!"
      });
      return;
    }
    var file = img.files[0];
    //是否是图片
    var imageType = /^image\//;
    if (!imageType.test(file.type)) {
      this.$Modal.warning({
        title: "警告",
        content: "请选择图片!"
      });
      return;
    }
    return file;
  }

5.鼠标悬浮显示预览和删除按钮

<div class="showImg" v-for="(item, index) in photoList" :key="item.src">
      <img
        class="addimg-items"
        v-show="photoList.length > 0"
        :src="item.src"
        @mouseenter="enter(item)"
        @mouseleave="leave(item)"
      />
      <div
        class="demo-upload-list-cover"
        v-show="item.imgHover"
        @mouseenter="enter(item)"
        @mouseleave="leave(item)"
      >
        <Icon type="ios-eye" @click="showImg(item.src)" />
        <Icon type="ios-trash" @click="reset(index)" />
      </div>
</div>

6.预览和删除JS操作

    //移入
    enter(item) {
      item.imgHover = true;
    },
    //移出
    leave(item) {
      item.imgHover = false;
    },
    //查看大图
    showImg(src) {
      this.visible = true;
      this.show.photo = src;
    },
    reset(index) {
      this.list.splice(index, 1);
      this.$emit("resetPic", this.list);
    }

7.图片预览,我使用了iView的对话框Modal来预览图片

<Modal title="图片详情" v-model="visible">
      <img :src="show.photo" v-if="visible" style="width: 100%" />
      <div slot="footer"></div>
</Modal>

最后附上全部代码

<style lang="less" scoped>
.showImg {
  position: relative;
  float: left;
  margin-right: 10px;
  .demo-upload-list-cover {
    width: 100px;
    height: 100px;
    padding: 33px 20px;
    i {
      font-size: 30px;
    }
  }
}
.addBtn {
  float: left;
  margin-right: 10px;
}
</style>

<template>
  <div>
    <form ref="uploadForm" id="uploadForm" style="display:inline;">
      <input
        type="file"
        id="fileId"
        ref="addPicFile"
        name="file"
        accept="image/jpg,image/jpeg,image/png,image/bmp"
        style="display:none;"
        @change="addPic"
      />
    </form>
    <div class="showImg" v-for="(item, index) in photoList" :key="item.src">
      <img
        class="addimg-items"
        v-show="photoList.length > 0"
        :src="item.src"
        @mouseenter="enter(item)"
        @mouseleave="leave(item)"
      />
      <div
        class="demo-upload-list-cover"
        v-show="item.imgHover"
        @mouseenter="enter(item)"
        @mouseleave="leave(item)"
      >
        <Icon type="ios-eye" @click="showImg(item.src)" />
        <Icon type="ios-trash" @click="reset(index)" />
      </div>
    </div>
    <img
      class="addimg-items addBtn"
      v-show="photoList.length < 5"
      src="@/assets/img/添加图片.png"
      @click="$refs.addPicFile.click()"
    />
    <Modal title="图片详情" v-model="visible">
      <img :src="show.photo" v-if="visible" style="width: 100%" />
      <div slot="footer"></div>
    </Modal>
  </div>
</template>

<script>
import common from "@/assets/js/common";
import Http from "@/utils/Network/Http";
export default {
  components: {},
  props: ["photo"],
  data() {
    return {
      visible: false,
      show: {
        photo: ""
      },
      photoList: [],
      list: []
    };
  },
  computed: {},
  watch: {},
  methods: {
    //移入
    enter(item) {
      item.imgHover = true;
    },
    //移出
    leave(item) {
      item.imgHover = false;
    },
    //查看大图
    showImg(src) {
      this.visible = true;
      this.show.photo = src;
    },
    //添加图片
    addPic() {
      let file = common.upload(this.$refs.addPicFile);
      let reader = new FileReader();
      reader.onload = e => {
        let img = new Image();
        img.src = e.target.result;
        img.onload = () => {
          let imgsrc = common.compress(img);
          this.$options.methods.uploadPic.bind(this)(imgsrc);
          this.$refs.addPicFile.value = "";
        };
      };
      reader.readAsDataURL(file);
    },
    uploadPic(data) {
      let res = Http.getAxios("POST", `/image/upload`, data);
      res.then(data => {
        this.list.push({
          src: data.message,
          imgHover: false
        });
        this.$emit("addPic", this.list);
      });
    },
    reset(index) {
      this.list.splice(index, 1);
      this.$emit("resetPic", this.list);
    },
    // 清空图片
    clearPic() {
      this.photoList = [];
      this.$emit("clearPic", this.photoList);
    }
  },
  mounted() {
    // 因为修改调用查询方法返回过来的数据会慢一点,所以我延迟赋值了,否则图片将不会展示
    setTimeout(() => {
      this.photoList = this.photo;
      this.list = this.photo;
    }, 300);
  }
};
</script>

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,376评论 6 491
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,126评论 2 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 156,966评论 0 347
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,432评论 1 283
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,519评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,792评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,933评论 3 406
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,701评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,143评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,488评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,626评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,292评论 4 329
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,896评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,742评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,977评论 1 265
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,324评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,494评论 2 348

推荐阅读更多精彩内容

  • 点击查看原文 Web SDK 开发手册 SDK 概述 网易云信 SDK 为 Web 应用提供一个完善的 IM 系统...
    layjoy阅读 13,700评论 0 15
  • 这两天和单位同事在上级单位加班,中途聊天,觉得果然人不可貌相。 同事是男生,家境优渥,本人名校研究生,叔婶都在上级...
    简小单_阅读 336评论 0 1
  • 沉重的心将你带回人世 惊喜与悲伤 它开始腐烂 苍蝇雀跃跳舞 他陷入黑暗 走向光明 他已无法保护自己 重新填充 上色...
    onlyCF阅读 210评论 0 0
  • 崇州和小北的故事 人生走走停停,浮浮沉沉,遇见多少人,遇见多少事,在意谁有忽略谁,在瞬息万变之...
    清平调小调阅读 419评论 2 2
  • 亲,思量了很久,决定还是要回你一封邮件。 就在你跟我说,你要辞职,去云南义工旅游那天,我就收到了你的邮件。 现在的...
    兮小样阅读 218评论 0 1