vue---图像上传/裁剪/预览/删除/查询

目录

一、案例功能

二、实现效果

三、知识点介绍

File

FileReader

FileReader.readAsDataURL(file)

FileReader.onload

VueCropper

四、案例思路

五、完整代码

参考文章


一、案例功能

1、查询图片:使用axios从服务器读取图片(url图片路径名),并排列显示。

2、新增图片:选择图像(FileReader)->图像裁剪(Vue-Cropper)->上传图像(base64)

3、删除图片

(ps:完整代码见篇末)

二、实现效果

点击【添加照片】方形区域打开文件夹选择图片,选择完成后弹出裁剪图片的对话框,点击【点击上传】按钮向后台提交图片。

选择图像:最多可上传3张照片,当没有照片上传时,【上传照片】区域仅有一个【添加照片;当第一张图片上传成功,【添加照片】出现在该图片后的第二个位置;当第二张图片上传成功,【添加照片】出现在该图片后的第三个位置;当第三张图片上传成功,【添加照片】不再出现。

图像裁剪:可对图片进行放大、缩小、左旋转、右旋转、下载及预览功能。

图像上传:上传满足图片要求的图片。

图像删除:鼠标移入图片出现删除图标,可点击进行删除操作,鼠标移出图片隐藏删除图标。

三、知识点介绍

File

File接口提供有关文件的信息,并允许网页中的 JavaScript 访问其内容。通常情况下, File 对象是来自用户在一个 <input>元素上选择文件后返回的FileList 对象,也可以是来自由拖放操作生成的 DataTranfer对象,或者来自HTMLCanvasElement 上的 mozGetAsFile() API。

File对象可以用来获取某个文件的信息,还可以用来读取这个文件的内容。

案例中,File对象来自用户在一个<input>元素上选择文件后返回的FileList对象【let file = this.$refs.photoFile.files[0];】

 <img v-show="(this.photoCount<3)" :src="this.uploadImage" @click="uploadPhoto" />
 <input type="file" hidden ref="photoFile" @change="fileChange" style="display: none;" />
 // 本地上传头像
    uploadPhoto() {
      this.$refs.photoFile.click();
    },
    // 修改头像
    fileChange(e) {
      let file = this.$refs.photoFile.files[0];
      if (/.(png|jpg|jpeg|JPG|JPEG)$/.test(file.name)) {
        let fr = new FileReader();
        fr.readAsDataURL(file);
        fr.onload = e => {
          // 将图像置于裁剪框中
          this.option.img = e.target.result;
          this.cropImageFormVisible = true;
          this.$refs.photoFile.value = "";
        };
      } else {
        this.$message({
          message: "请选择符合格式要求的图片",
          type: "warning"
        });
        this.$refs.photoFile.value = "";
      }
    },

File 对象是来自用户通过【 <input type="file" hidden ref="photoFile" @change="fileChange" style="display: none;" />】元素上选择文件后返回的 FileList 对象,本案例只能一次上传一张图片,因此files.length=1。可以通过files[index]获取我们选择的file对象。

当为<input>添加属性【 multiple="multiple"】,即【<input type="file" hidden multiple="multiple" ref="photoFile" @change="fileChange" style="display: none;" />】时,可选择N个文件,files.length=N。

FileReader

FileReader:FileReader对象允许Web应用程序异步读取存储在用户计算机上的文件(或原始数据缓冲区)的内容,使用 File 或 Blob对象指定要读取的文件或数据。File 对象是特殊类型的 Blob,且可以用在任意的 Blob 类型的 context 中。

FileReader.readAsDataURL(file)

FileReader.readAsDataURL(file)开始读取指定的Blob中的内容。一旦完成,result属性中将包含一个data: URL格式的Base64字符串以表示所读取文件的内容。

【this.option.img = e.target.result;】 e.target.result为base64形式的字符串,称之为DataURL对象。在Data URL协议中,图片被转换成base64编码的字符串形式,并存储在URL中。

FileReader.onload

FileReader.onload处理load事件,在读取操作开始时触发。

VueCropper

参见:vue---vueCropper实现图像裁剪

四、案例思路

1、通过设置一个标志(true/false)控制【添加照片】是否显示,当查询到后台传过来的图片个数<3时,标志为true,【添加照片】显示,否则标志为false,【添加照片】隐藏。

2、当鼠标移入图像时,出现删除按钮,鼠标移出图像时,删除按钮消失。通过css样式实现,设置【删除图标】样式为不可见【.delete-img {display: none;}】,当【li:hover】时设置【删除图标】样式可见【display: block】即可。

五、完整代码

<template>
  <div class="personal">
    <div class="content">
      <!-- 1.标题及图像说明 -->
      <div class="content-desc">
        <div class="title">上传照片</div>
        <div class="desc">照片要求为清晰无遮挡的人脸正脸照,格式为jpg/jpeg/png,最多可上传3张照片</div>
      </div>
      <!-- 2.图像区域 -->
      <ul class="content-image">
        <li v-for="(item, index) in image" :key="index">
          <img :src="item.imageUrl" />
          <!-- 删除图标 -->
          <div class="delete-img">
            <i class="el-icon-delete" @click="deleteImage(index,item.id)"></i>
          </div>
        </li>
        <!-- 控制最多可上传三张图片 -->
        <img
          class="upload-img"
          v-show="(this.photoCount<3)"
          :src="this.uploadImage"
          @click="uploadPhoto"
        />
      </ul>
      <input type="file" hidden ref="photoFile" @change="fileChange" style="display: none;" />
    </div>
    <!-- 上传图像前调整图像的尺寸 -->
    <el-dialog title="修改头像" :visible.sync="cropImageFormVisible" class="cropImageForm" width="50%">
      <div class="img-crop">
        <!-- 1.截图区域 -->
        <div class="imgCrop-content">
          <div class="cropper-content">
            <vueCropper
              ref="cropper"
              :img="option.img"
              :outputSize="option.size"
              :outputType="option.outputType"
              :info="true"
              :full="option.full"
              :canMove="option.canMove"
              :canMoveBox="option.canMoveBox"
              :original="option.original"
              :autoCrop="option.autoCrop"
              :autoCropWidth="option.autoCropWidth"
              :autoCropHeight="option.autoCropHeight"
              :fixedBox="option.fixedBox"
              @realTime="realTime"
              @imgLoad="imgLoad"
            ></vueCropper>
          </div>
          <div class="preview-content">
            <div class="show-preview">
              <div :style="previews.div" class="preview">
                <img :src="previews.url" :style="previews.img" />
              </div>
            </div>
            <p class="desc">预览图片</p>
          </div>
        </div>
        <!-- 2.操作按钮区域 -->
        <div class="btn-content">
          <input class="btn" type="button" value="+" title="放大" @click="changeScale(1)" />
          <input class="btn" type="button" style value="-" title="缩小" @click="changeScale(-1)" />
          <input class="btn" type="button" value="↺" title="左旋转" @click="rotateLeft" />
          <input class="btn" type="button" value="↻" title="右旋转" @click="rotateRight" />
          <input class="btn" type="button" value="↓" title="下载" @click="down('blob')" />
        </div>
      </div>
      <div class="btn-footer">
        <el-button @click="cropImageFormVisible= false" size="small">取 消</el-button>
        <el-button type="danger" @click="submitPhoto" size="small">点击上传</el-button>
      </div>
    </el-dialog>
    <!-- 删除对话框 -->
    <el-dialog title="删除" :visible.sync="deleteImageFormVisible" width="30%" class="deleteRoleForm">
      <span>是否删除该照片?</span>
      <span slot="footer" class="dialog-footer">
        <el-button size="mini" @click="deleteImageFormVisible = false">取 消</el-button>
        <el-button size="mini" type="primary" @click="submitDeleteImage">确 定</el-button>
      </span>
    </el-dialog>
  </div>
</template>
<script>
import { VueCropper } from "vue-cropper";
import {
  imageAdd,
  imageQuery,
  imageDelete,
  dictListQuery
} from "../../api/http";
export default {
  data() {
    return {
      cropImageFormVisible: false,
      deleteImageFormVisible: false,
      deleteImgId: null,
      deleteIndex: null,
      image: [
        // {
        //   imageUrl:
        //     "https://cube.elemecdn.com/6/94/4d3ea53c084bad6931a56d5158a48jpeg.jpeg",
        //   id: 1
        // },
        // {
        //   imageUrl:
        //     "https://fuss10.elemecdn.com/a/3f/3302e58f9a181d2509f3dc0fa68b0jpeg.jpeg",
        //   id: 2
        // },
        // {
        //   imageUrl:
        //     "https://fuss10.elemecdn.com/a/3f/3302e58f9a181d2509f3dc0fa68b0jpeg.jpeg",
        //   id: 3
        // }
      ],
      photoCount: 0,
      uploadImage: "",
      //剪切图片上传
      previews: {},
      option: {
        img: "",
        outputSize: 1, //剪切后的图片质量(0.1-1)
        full: false, //输出原图比例截图 props名full
        outputType: "png",
        canMove: true,
        original: false,
        canMoveBox: true,
        autoCrop: true,
        autoCropWidth: 150,
        autoCropHeight: 150,
        fixedBox: true
      },
      downImg: "#",
      host: "" //存放图像的服务器ip及端口
    };
  },
  components: {
    VueCropper
  },
  created() {
    //  uploadImage用于存放“添加照片”图片base64,
    this.uploadImage =
      "data:image/png;base64,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";
    this.photoCount = this.image.length;
    // *******查询系统参数配置--用于获取图像服务器ip及端口*****/
    let param1 = {
      token: this.$store.state.token,
      tag: "系统参数配置",
      currentPage: 1,
      pageSize: 10
    };
    dictListQuery(param1).then(res => {
      var hostArray = res.data.result.records.filter(function(fh) {
        return fh.name === "faceImage_server_host";
      });
      this.host = hostArray[0].value;
      //******查询人脸图像信息********
      this.getImageData();
    });
  },
  methods: {
    //******查询人脸图像信息********
    getImageData() {
      // this.image = [];
      let param = {
        token: this.$store.state.token,
        currentPage: 1,
        pageSize: 10
      };
      imageQuery(param).then(res => {
        if (res.data.respCode == "00000") {
          var urlArray = res.data.result.records;
          this.image = urlArray;
          for (var i = 0; i < urlArray.length; i++) {
            this.image[i].imageUrl = this.host + urlArray[i].url;
          }
          this.photoCount = urlArray.length;
        } else {
          this.$message.error(res.data.respDesc);
        }
      });
    },
    // 本地上传头像
    uploadPhoto() {
      this.$refs.photoFile.click();
    },
    // 修改头像
    fileChange(e) {
      console.log("输出files:", this.$refs.photoFile.files);
      let file = this.$refs.photoFile.files[0];
      if (/.(png|jpg|jpeg|JPG|JPEG)$/.test(file.name)) {
        let fr = new FileReader();
        fr.readAsDataURL(file);
        fr.onload = e => {
          // 将图像置于裁剪框中
          console.log("输出e:", e);
          this.option.img = e.target.result;
          this.cropImageFormVisible = true;
          this.$refs.photoFile.value = "";
        };
      } else {
        this.$message({
          message: "请选择符合格式要求的图片",
          type: "warning"
        });
        this.$refs.photoFile.value = "";
      }
    },
    // 上传图像
    submitPhoto() {
      this.$refs.cropper.getCropData(data => {
        let param = {
          token: this.$store.state.token,
          image: data
        };
        imageAdd(param).then(res => {
          // console.log("提交新增图片:", res);
          if (res.data.respCode == "00000") {
            this.$message.success(res.data.respDesc);
            this.photoCount++;
            this.cropImageFormVisible = false;
            this.getImageData();
          } else {
            this.$message.error(res.data.respDesc);
          }
        });
      });
    },
    // 删除图片
    deleteImage(index, id) {
      this.deleteImgId = id;
      this.deleteIndex = index;
      this.deleteImageFormVisible = true;
    },
    // 提交删除图片
    submitDeleteImage() {
      this.deleteImageFormVisible = false;
      let param = {
        token: this.$store.state.token,
        imageId: this.deleteImgId
      };
      imageDelete(param).then(res => {
        // console.log(" 提交删除:", res);
        if (res.data.respCode == "00000") {
          // this.image.splice(this.deleteIndex, 1);
          this.photoCount--;
          this.$message.success(res.data.respDesc);
        } else {
          this.$message.error(res.data.respDesc);
        }
        this.getImageData();
      });
    },
    //放大/缩小
    changeScale(num) {
      num = num || 1;
      this.$refs.cropper.changeScale(num);
    },
    //左旋转
    rotateLeft() {
      this.$refs.cropper.rotateLeft();
    },
    //右旋转
    rotateRight() {
      this.$refs.cropper.rotateRight();
    },
    // 实时预览函数
    realTime(data) {
      this.previews = data;
    },
    //下载图片
    down(type) {
      var aLink = document.createElement("a");
      aLink.download = "author-img";
      if (type === "blob") {
        this.$refs.cropper.getCropBlob(data => {
          this.downImg = window.URL.createObjectURL(data);
          aLink.href = window.URL.createObjectURL(data);
          aLink.click();
        });
      } else {
        this.$refs.cropper.getCropData(data => {
          this.downImg = data;
          aLink.href = data;
          aLink.click();
        });
      }
    },
    imgLoad(msg) {}
  }
};
</script>
<style lang="less">
.personal {
  margin: 10px 0;
  padding: 10px;
  background: #f0f0f0;
  width: 100%;
  height: 100%;
  box-sizing: border-box;
  overflow-y: hidden;
  border-radius: 3px;
  padding-bottom: 20px;
  .content {
    background-color: #fff;
    width: 100%;
    height: 100%;
    border-radius: 6px;
    padding: 10px;
    // overflow-y: scroll;
    overflow: hidden;
    display: flex;
    padding: 10px 0;
    flex-direction: column;
    //  1.标题及图像说明
    .content-desc {
      margin: 0px 10px;
      .title {
        font-size: 16px;
        border-left: 5px solid #2d8cf0;
        padding-left: 10px;
        margin-bottom: 16px;
      }
      .desc {
        margin-left: 18px;
      }
    }
    // 2.图像区域
    .content-image {
      display: flex;
      justify-content: rows;
      margin: 20px 30px;
      li {
        width: 180px;
        height: 180px;
        margin-right: 20px;
        position: relative;
        .delete-img {
          display: none;
        }
        &:hover {
          .delete-img {
            display: block;
            position: absolute;
            width: 180px;
            height: 40px;
            line-height: 40px;
            left: 0px;
            top: 140px;
            background: rgba(59, 60, 61, 0.5);
            // box-sizing: content-box;
            z-index: 999;
            cursor: pointer;
            text-align: right;
            i {
              margin: 8px 10px 0 0;
              display: block;
              font-size: 24px;
              color: white;
            }
          }
        }
      }
      img {
        width: 180px;
        height: 180px;
        border-radius: 4px;
      }
      .upload-img:hover {
        border: 1px dashed #92cccc;
      }
    }
  }
  // 裁剪图像对话框
  .cropImageForm {
    .img-crop {
      // 1.截图区域
      .imgCrop-content {
        margin: 0 20px;
        display: flex;
        display: -webkit-flex;
        justify-content: flex-start;
        -webkit-justify-content: flex-start;
        .cropper-content {
          width: 350px;
          height: 350px;
          margin-right: 40px;
        }
        .preview-content {
          .show-preview {
            // border: 1px solid #ccc;
            box-sizing: border-box;
            width: 150px;
            height: 150px;
            overflow: hidden;
            flex: 1;
            -webkit-flex: 1;
            display: flex;
            display: -webkit-flex;
            justify-content: center;
            -webkit-justify-content: center;
            .preview {
              overflow: hidden;
              border-radius: 50%;
              border: 1px solid #cccccc;
              background: #fff;
              margin-left: 0px;
            }
          }
          .desc {
            margin-top: 10px;
            text-align: center;
          }
          .el-button {
            margin: 10px 40px;
          }
        }
      }
      // 2.操作按钮区域
      .btn-content {
        width: 350px;
        margin: 10px 20px;
        text-align: center;
        // #uploads {
        //   position: absolute;
        //   clip: rect(0 0 0 0);
        // }
        .btn {
          height: 32px;
          width: 32px;
          font-size: 20px;
          margin: 3px 5px;
          background-color: #fff;
          border: 1px solid #999;
          border-radius: 4px;
        }
      }
    }
    .btn-footer {
      width: 100%;
      text-align: right;
      padding-right: 20px;
      margin-top: -20px;
    }
  }
}
</style>

参考文章

Html5——File、FileReader、Blob、Fromdata对象

MDN---File

Vue项目图片剪切上传——vue-cropper的使用

  • 0
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值