vue-cropper插件实现图片截取上传组件封装


Posted in Vue.js onMay 27, 2021

基于vue-cropper插件实现图片截取上传组件封装的具体代码,供大家参考,具体内容如下

需求场景:

后台开发需要上传图片并进行相应比例尺寸图片的截取,本组件开发采用Ant Design Vue组件库搭配vue-cropper插件进行封装

实现如下

vue-cropper插件实现图片截取上传组件封装

vue-cropper插件实现图片截取上传组件封装

html

<template>
  <div>
    <a-upload
      name="avatar"
      list-type="picture-card"
      class="avatar-uploader"
      :show-upload-list="false"
      :custom-request="customRequest"
      :before-upload="beforeUpload"
      :style="`width: ${width}; height: ${height};`"
    >
      <img
        v-if="imageUrl && !loading"
        :src="imageUrl"
        alt="avatar"
        :style="`width: ${width}; height: ${height};`"
      />
      <div v-else>
        <a-icon :type="loading ? 'loading' : 'plus'" />
        <div class="ant-upload-text">上传图片</div>
      </div>
    </a-upload>
    <a-modal
      v-model="imageCut.isShowModal"
      title="图片截取"
      width="400px"
      @ok="finish"
      @cancel="imageCut.close"
    >
      <div class="cropper-content" v-if="imageCut.isShowModal">
        <div class="cropper" style="text-align:center">
          <vueCropper
            ref="cropper"
            :img="imageCut.imgFile"
            :outputSize="outputSize"
            :outputType="outputType"
            :info="info"
            :full="full"
            :canMove="canMove"
            :canMoveBox="canMoveBox"
            :original="original"
            :autoCrop="autoCrop"
            :fixed="fixed"
            :fixedNumber="fixedNumber"
            :centerBox="centerBox"
            :infoTrue="infoTrue"
            :fixedBox="fixedBox"
          ></vueCropper>
        </div>
      </div>
    </a-modal>
  </div>
</template>

js

<script>
import { uploadImage } from '@/api/common'
import { VueCropper } from "vue-cropper";
export default {
  name: 'ImageUpload',
  components: { VueCropper },
  data() {
    return {
      loading: false,
      imageCut: {
        isShowModal: false,
        imgFile: '',
        init: imgFile => {
          this.imageCut.imgFile = imgFile
          this.imageCut.isShowModal = true
        },
        close: () => {
          this.imageCut.imgFile = ''
          this.imageCut.isShowModal = false
        }
      }
    }
  },
  props: {
    imageUrl: String,
    width: {
      type: String,
      default: '100px'
    },
    height: {
      type: String,
      default: '100px'
    },
    canCut: {
      type: Boolean,
      default: false
    },
    info: {
      type: Boolean,
      default: false
    }, // 裁剪框的大小信息
    outputSize: {
      type: Number,
      default: 0.8
    }, // 裁剪生成图片的质量
    outputType: {
      type: String,
      default: 'jpeg'
    }, // 裁剪生成图片的格式
    canScale: {
      type: Boolean,
      default: true
    }, // 图片是否允许滚轮缩放
    autoCrop: {
      type: Boolean,
      default: true
    }, // 是否默认生成截图框
    // autoCropWidth: 300, // 默认生成截图框宽度
    // autoCropHeight: 200, // 默认生成截图框高度
    fixedBox: {
      type: Boolean,
      default: false
    }, // 固定截图框大小 不允许改变
    fixed: {
      type: Boolean,
      default: true
    }, // 是否开启截图框宽高固定比例
    fixedNumber: {
      type: Array,
      default: () => [1, 1]
    }, // 截图框的宽高比例
    full: {
      type: Boolean,
      default: true
    }, // 是否输出原图比例的截图
    canMove: {
      type: Boolean,
      default: false
    },
    canMoveBox: {
      type: Boolean,
      default: true
    }, // 截图框能否拖动
    original: {
      type: Boolean,
      default: false
    }, // 上传图片按照原始比例渲染
    centerBox: {
      type: Boolean,
      default: true
    }, // 截图框是否被限制在图片里面
    infoTrue: {
      type: Boolean,
      default: true
    } // true 为展示真实输出图片宽高 false 展示看到的截图框宽高
  },
  methods: {
    beforeUpload(file) {
      const isJpgOrPng = file.type === 'image/jpeg' || file.type === 'image/png'
      if (!isJpgOrPng) {
        this.$message.error('请上传JPG或PNG文件!')
      }
      const isLt2M = file.size / 1024 / 1024 < 2
      if (!isLt2M) {
        this.$message.error('请上传2MB以下文件!')
      }
      return isJpgOrPng && isLt2M
    },
    customRequest(file) {
      if (this.canCut) {
        this.readFile(file.file)
      } else {
        this.loading = true
        const formData = new FormData()
        formData.append('fileIdcard', file.file)
        uploadImage(formData).then(res => {
          this.loading = false
          this.$emit('uploadSuccess', res.ossUrl)
        })
      }
    },
    readFile(file) {
      var reader = new FileReader()
      reader.readAsDataURL(file)
      reader.onload = () => {
        this.imageCut.init(reader.result)
      }
    },
    finish() {
      this.$refs.cropper.getCropBlob(data => {
        this.loading = true
        // 上传阿里云服务器
        const formData = new FormData()
        formData.append('fileIdcard', data)
        uploadImage(formData).then(res => {
          this.imageCut.close()
          this.loading = false
          this.$emit('uploadSuccess', res.ossUrl)
        })
      })
    }
  }
}
</script>

css

<style lang="less">
.avatar-uploader > .ant-upload {
  width: 100%;
  height: 100%;
}
.ant-upload-select-picture-card i {
  font-size: 32px;
  color: #999;
}

.ant-upload-select-picture-card .ant-upload-text {
  margin-top: 8px;
  color: #666;
}
.cropper-content {
  .cropper {
    width: auto;
    height: 400px;
  }
}
</style>

组件使用及说明

<image-upload
        :imageUrl="form.diagramUrl"
        @uploadSuccess="uploadSuccess"
        width="160px"
        height="90px"
        :can-edit="canCut"
        :fixed-number="[16,9]"
      />

组件调用时需传入canEdit属性,指定组件是否启动图片选取后的裁剪功能,默认值为不启用裁剪;需裁剪时可传入fixedNumber属性,定义裁剪框的宽高比

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Vue.js 相关文章推荐
vue3.0+vue-router+element-plus初实践
Dec 02 Vue.js
用vue设计一个日历表
Dec 03 Vue.js
vue从后台渲染文章列表以及根据id跳转文章详情详解
Dec 14 Vue.js
手写Vue源码之数据劫持示例详解
Jan 04 Vue.js
vue 动态添加的路由页面刷新时失效的原因及解决方案
Feb 26 Vue.js
vue-cli中实现响应式布局的方法
Mar 02 Vue.js
Vue接口封装的完整步骤记录
May 14 Vue.js
Vue全局事件总线你了解吗
Feb 24 Vue.js
教你部署vue项目到docker
Apr 05 Vue.js
vue修饰符.capture和.self的区别
Apr 22 Vue.js
vue实现在data里引入相对路径
Jun 05 Vue.js
Vue深入理解插槽slot的使用
Aug 05 Vue.js
HTML+VUE分页实现炫酷物联网大屏功能
Vue实现动态查询规则生成组件
详解vue身份认证管理和租户管理
vue点击弹窗自动触发点击事件的解决办法(模拟场景)
vue-element-admin项目导入和导出的实现
May 21 #Vue.js
vue2实现provide inject传递响应式
May 21 #Vue.js
vue使用节流函数的踩坑实例指南
You might like
PHP最常用的2种设计模式工厂模式和单例模式介绍
2012/08/14 PHP
PHP实现求两个字符串最长公共子串的方法示例
2017/11/17 PHP
通过MSXML2自动获取QQ个人头像及在线情况(给初学者)
2007/01/22 Javascript
JQuery读取XML文件数据并显示的实现代码
2009/12/16 Javascript
iframe的父子窗口之间的对象相互调用基本用法
2013/09/03 Javascript
JS实现程序暂停与继续功能代码解读
2013/10/10 Javascript
jQuery+css3动画属性制作猎豹浏览器宽屏banner焦点图
2015/03/16 Javascript
基于jquery实现简单的分页控件
2016/03/17 Javascript
拥Bootstrap入怀——导航栏篇
2016/05/30 Javascript
浅谈javascript中new操作符的原理
2016/06/07 Javascript
JS实现的按钮点击颜色切换功能示例
2017/10/19 Javascript
基于Axios 常用的请求方法别名(详解)
2018/03/13 Javascript
详解浏览器缓存和webpack缓存配置
2018/07/06 Javascript
解决vue的 v-for 循环中图片加载路径问题
2018/09/03 Javascript
p5.js绘制创意自画像
2019/11/04 Javascript
详解js中的原型,原型对象,原型链
2020/07/16 Javascript
JavaScript实现雪花飘落效果
2020/12/27 Javascript
[31:55]完美世界DOTA2联赛循环赛 IO vs GXR BO2第一场 11.04
2020/11/05 DOTA
[51:15]完美世界DOTA2联赛PWL S2 PXG vs Magma 第一场 11.21
2020/11/24 DOTA
[32:36]完美世界DOTA2联赛PWL S3 LBZS vs CPG 第二场 12.12
2020/12/16 DOTA
Python导入txt数据到mysql的方法
2015/04/08 Python
pyqt5简介及安装方法介绍
2018/01/31 Python
TensorFlow实现iris数据集线性回归
2018/09/07 Python
安装Pycharm2019以及配置anconda教程的方法步骤
2019/11/11 Python
python抓取多种类型的页面方法实例
2019/11/20 Python
python怎么自定义捕获错误
2020/06/29 Python
Looking4Parking美国:全球排名第一的机场停车比较品牌
2019/08/26 全球购物
Richards网上商店:当代时尚,遍布巴西
2019/11/03 全球购物
优秀应届毕业生自荐信
2013/11/16 职场文书
中学运动会广播稿
2014/01/19 职场文书
上班上网检讨书
2014/01/29 职场文书
北京故宫导游词
2015/01/31 职场文书
演讲开场白台词大全
2015/05/29 职场文书
毕业生入职感言
2015/07/31 职场文书
关于销售人员的年终工作总结要点
2019/08/15 职场文书
python+pyhyper实现识别图片中的车牌号思路详解
2022/12/24 Python