vue中 通过cropperjs 实现图片裁剪

cropperjs 官方文档: https://www.npmjs.com/package/cropperjs

最终效果图

在这里插入图片描述

具体实现

  1. 安装 cropperjs
npm install cropperjs --save
  1. 引入 cropperjs
import Cropper from 'cropperjs'
import 'cropperjs/dist/cropper.css'
  1. 自定义 裁剪图片弹窗 组件
<template>
  <el-dialog title="图片裁剪" :visible.sync="dialogVisible" width="1300px" :append-to-body="true">
    <div class="cropper-content">
      <!-- 剪裁框 -->
      <div class="cropper">
        <img ref="image" :src="imgFile" alt="">
      </div>
      <!-- 预览框 -->
      <div
        class="show-preview"
        :style="{
          overflow: 'hidden',
          margin: '0 25px',
          display: 'flex',
          'align-items': 'center'
        }"
      >
        <div class="preview before" />
      </div>
    </div>
    <div class="footer-btn">
      <!-- 缩放旋转按钮 -->
      <div class="scope-btn">
        <el-tooltip class="item" effect="dark" content="放大" placement="top">
          <el-button icon="el-icon-zoom-in" @click="cropperzoom(0.05)" />
        </el-tooltip>
        <el-tooltip class="item" effect="dark" content="缩小" placement="top">
          <el-button icon="el-icon-zoom-out" @click="cropperzoom(-0.05)" />
        </el-tooltip>
        <el-tooltip
          class="item"
          effect="dark"
          content="逆时针旋转"
          placement="top"
        >
          <el-button
            icon="el-icon-refresh-left"
            @click="cropperRotate(-90)"
          />
        </el-tooltip>
        <el-tooltip
          class="item"
          effect="dark"
          content="顺时针旋转"
          placement="top"
        >
          <el-button
            icon="el-icon-refresh-right"
            @click="cropperRotate(90)"
          />
        </el-tooltip>
      </div>
      <div class="upload-btn">
        <el-button class="btn" @click="closeCropper">取消</el-button>
        <el-button
          type="primary"
          @click="sureSave()"
        >确定</el-button>
      </div>
    </div>
  </el-dialog>
</template>

<script>
import Cropper from 'cropperjs'
import 'cropperjs/dist/cropper.css'

export default {
  props: {
    imgFile: {
      type: String,
      default: ''
    },
    visible: {
      type: Boolean,
      default: false
    }
  },
  data() {
    return {
      myCropper: null,
      afterImg: ''
    }
  },
  computed: {
    dialogVisible: {
      get() {
        return this.visible
      },
      set(val) {
        this.$emit('update:visible', val)
      }
    }
  },
  watch: {
    imgFile(val) {
      if (val) {
        setTimeout(() => {
          if (this.myCropper) {
          	// 这里很重要,不然弹窗再次弹出后图片不会更新
            this.myCropper.destroy()
            this.init()
          } else {
            this.init()
          }
        })
      }
    }
  },
  methods: {
    closeCropper() {
      this.$emit('closeCropper')
    },
    init() {
      this.myCropper = new Cropper(this.$refs.image, {
        viewMode: 1,
        dragMode: 'move',
        preview: '.before',
        background: false,
        autoCropArea: 0.8,
        zoomOnWheel: true
      })
    },
    sureSave() {
      this.afterImg = this.myCropper
        .getCroppedCanvas({
          imageSmoothingQuality: 'high'
        })
        .toDataURL('image/jpeg')
      this.$emit('cropperImg', this.base64ToBlob(this.afterImg))
    },
    base64ToBlob(code) {
      const parts = code.split(';base64,')
      const contentType = parts[0].split(':')[1]
      const raw = window.atob(parts[1])
      const rawLength = raw.length

      const uInt8Array = new Uint8Array(rawLength)

      for (let i = 0; i < rawLength; ++i) {
        uInt8Array[i] = raw.charCodeAt(i)
      }
      return new Blob([uInt8Array], {
        type: contentType
      })
    },
    // 缩放
    cropperzoom(val) {
      this.myCropper.zoom(val)
    },
    // 旋转
    cropperRotate(val) {
      this.myCropper.rotate(val)
    }
  }
}
</script>
  <style lang="scss" scoped>
  .cropper {
    border: 1px solid #fff;
    background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAAA3NCSVQICAjb4U/gAAAABlBMVEXMzMzTjRV2AAAACXBIWXMAAArrAAAK6wGCiw1aAAAAHHRFWHRTb2Z0d2FyZQBBZG9iZSBGaXJld29ya3MgQ1M26LyyjAAAABFJREFUCJlj+M/AgBVhF/0PAH6/D/HkDxOGAAAAAElFTkSuQmCC);
    img{
      width: 100%;
      opacity: 0;
    }
  }
  .cropper-content {
    display: flex;
    display: -webkit-flex;
    justify-content: flex-end;
    -webkit-justify-content: flex-end;
  }
  .cropper-content .cropper {
    // width: 550px;
    // height: 400px;
    width: 600px;
    height: 450px;
    overflow: hidden;
  }
  .cropper-content .show-preview {
    flex: 1;
    -webkit-flex: 1;
    display: flex;
    display: -webkit-flex;
    justify-content: center;
    -webkit-justify-content: center;
    overflow: hidden;
    /* border: 1px solid #cccccc; */
    background: #cccccc;
    margin-left: 40px;
  }
  .preview {
    overflow: hidden;
    border: 1px solid #468ac8;
    background: #cccccc;
  }
  .footer-btn {
    margin-top: 30px;
    display: flex;
    display: -webkit-flex;
    justify-content: flex-end;
    -webkit-justify-content: flex-end;
  }
  .footer-btn .scope-btn {
    width: 260px;
    display: flex;
    display: -webkit-flex;
    justify-content: space-between;
    -webkit-justify-content: space-between;
  }
  .footer-btn .scope-btn span {
    display: inline-block;
    padding: 10px;
    box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
    border-radius: 5px;
    background: #fff;
    cursor: pointer;
  }
  .footer-btn .scope-btn span i {
    font-size: 32px;
    color: #333333;
  }
  .footer-btn .upload-btn {
    flex: 1;
    -webkit-flex: 1;
    display: flex;
    display: -webkit-flex;
    justify-content: flex-end;
    -webkit-justify-content: flex-end;
    margin-right: 25px;
    .btn {
        padding: 0 10px;
        height: 29px;
    }
  }
  .solide {
    margin-left: 25px;
    width: 200px;
  }
  .before {
    width: 100%;
    height: 100%;
    overflow: hidden;
  }
  </style>

  1. 使用组件
import cropper from './cropper.vue'

<cropper :imgFile="originBase64" :visible.sync="cropperVisible" v-bind="$attrs" @cropperImg="cropperImg" @closeCropper="closeCropper" v-on="$listeners" />

参考地址:https://www.jianshu.com/p/5f5aafe9e895

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值