一个优雅的图片裁剪插件vue-cropper,很方便新手入手

安装

npm install vue-cropper

使用

import VueCropper from vue-cropper


import axios from 'axios'
const host = 'xxx';

//预上传
export function uploadBefore(md5, size, ext) {
    const url = host + "/file/upload/before";
    return axios.post(url, {
        md5: md5,
        size: size,
        ext: ext
    }).then((res) => {
        return Promise.resolve(res)
    })
}
//保存文件
export function saveImage(key) {
    const url = host + "/file/save";
    return axios.put(url, {
        key: key
    }).then((res) => {
        return Promise.resolve(res)
    })
}

import * as qiniu from 'qiniu-js'
import browserMD5File from 'browser-md5-file'
import { uploadBefore as preUploadFile, saveImage as saveFile } from 'api/uploadImage'

export function uploadFile(file) {
  return new Promise((resolve, reject) => {
    function checkError(res) {
      if (res.data.code !== 0) {
        reject(new Error(res.data.msg))
      }
    }

    // 预上传
    new Promise(preResolve => {
      // 生成文件 MD5 以便校验服务器上是否存在该文件
      browserMD5File(file, function (err, md5) {
        // size 转换成 kb
        const size = file.size / 1024
        const ext = file.name.substr(file.name.lastIndexOf('.') + 1)

        preUploadFile(md5, size, ext).then(res => {
          checkError(res)

          // 当 file_id 存在时表示文件已经上传过,所以进行秒传处理
          if (res.data.data.file_id) {
            resolve(res.data.data)
          } else {
            preResolve(res.data.data)
          }
        })
      })
    }).then(res => {
      let observable = qiniu.upload(file, res.key, res.token)
      return new Promise((uploadResolve, uploadReject) => {
        observable.subscribe({
          next(res) {
          },
          error(err) {
            uploadReject(err)
          },
          complete(res) {
            uploadResolve(res)
          }
        })
      })
    }).then(res => {
      const key = res.key

      return saveFile(key)
    }).then(res => {
      checkError(res)

      resolve(res.data.data)
    }).catch(e => {
      console.log(e)
      this.$message.warning(e.message)
    })
  })
}

<template>
  <div>
     <!-- element 上传图片按钮 -->
      <el-upload class="uploader"
                       action
                       :show-file-list="false"
                       :on-success="handleUploadSuccess"
                       :http-request="customUpload">
              <img v-if="fileinfo.url"
                   :src="fileinfo.url"
                   class="upload">
              <i v-else
                 class="el-icon-plus uploader-icon" />
            </el-upload>
......
    <!-- vueCropper 剪裁图片实现-->
    <div class="vue-cropper-box"
         v-if="isShowCropper">
      <div class="vue-cropper-content">
        <vueCropper ref="cropper"
                    :img="option.img"
                    :outputSize="option.outputSize"
                    :outputType="option.outputType"
                    :info="option.info"
                    :canScale="option.canScale"
                    :autoCrop="option.autoCrop"
                    :autoCropWidth="option.autoCropWidth"
                    :autoCropHeight="option.autoCropHeight"
                    :fixed="option.fixed"
                    :fixedNumber="option.fixedNumber"></vueCropper>
      </div>
      <el-button v-if="isShowCropper"
                 type="danger"
                 @click="onCubeImg">确定裁剪图片</el-button>

    </div>
  </div>
</template>

<script>
import VueCropper from "vue-cropper"
import { uploadFile } from './uploadFile'

export default {
  components: {
    VueCropper
  },
  data() {
    return {
     //裁剪组件的基础配置option
      option: {
        img: '',                         //裁剪图片的地址
        info: true,                      //裁剪框的大小信息
        outputSize: 1,                   // 裁剪生成图片的质量
        outputType: 'jpeg',              //裁剪生成图片的格式
        canScale: false,                 // 图片是否允许滚轮缩放
        autoCrop: true,                  // 是否默认生成截图框
        autoCropWidth: 150,              // 默认生成截图框宽度
        autoCropHeight: 150,             // 默认生成截图框高度
        fixed: false,                    //是否开启截图框宽高固定比例
        fixedNumber: [4, 4]              //截图框的宽高比例
      },
      isShowCropper: false,            //是否显示截图框
      fileUpload: null,
      fileinfo: {},
      form: {},
    }
},
  methods: {
    //上传按钮上传成功执行事件
    handleUploadSuccess(response, file, fileList) {
      this.log('Upload response is %o', response)
      this.fileinfo = response

      this.fileUpload = file;

      //上传成功后将图片地址赋值给裁剪框显示图片
      this.$nextTick(() => {
        this.option.img = file.url;
        this.isShowCropper = true
      })
    },

    // 确定裁剪图片
    onCubeImg() {
      // 获取cropper的截图的base64 数据
      this.$refs.cropper.getCropData(data => {
        this.fileinfo.url = data
        this.isShowCropper = false

       //先将显示图片地址清空,防止重复显示
        this.option.img = ''

       //将剪裁后base64的图片转化为file格式
        let file = this.convertBase64UrlToBlob(data)
        file.name = this.fileUpload.name

        //将剪裁后的图片执行上传
        this.uploadFile(file).then(res => {
          this.form.content = res.file_id    //将上传的文件id赋值给表单from的content
        })

      })
    },

    // 将base64的图片转换为file文件
    convertBase64UrlToBlob(urlData) {
      let bytes = window.atob(urlData.split(',')[1]);//去掉url的头,并转换为byte
      //处理异常,将ascii码小于0的转换为大于0
      let ab = new ArrayBuffer(bytes.length);
      let ia = new Uint8Array(ab);
      for (var i = 0; i < bytes.length; i++) {
        ia[i] = bytes.charCodeAt(i);
      }
      return new Blob([ab], { type: 'image/jpeg' });
    },

代码暂时都是从项目中抽出来的,只适合借鉴参考,等有时间再单独将这些功能单独写项目,欢迎大家提供更好用的方法或指出不足之处,一起进步。

Logo

前往低代码交流专区

更多推荐