vue中实现图片裁剪

在现代Web应用中,图片处理是一个常见的需求。本文将介绍如何使用Vue.js结合Cropper.js实现一个简单的图片裁剪功能。以下是实现该功能的完整代码。

代码实现

<template>
  <div class="c-copper-container" :class="{'wd260' : type == 'articlesubmit'}">
    <div class="c-copper-box">
      <div class="c-image-box">
        <img :src="copperImgUrl" id="image" alt="暂无图片">
      </div>
      <div class="c-preview-box">
        <div class="img-preview">
          <div class="title">预览</div>
          <div class="preview"><img :src="copperImgUrl" alt="暂无图片"></div>
        </div>
        <div class="img-upload-btn">
          <el-button icon="cs-format-image" size="mini" plain>上传图片</el-button>
          <input type="file" accept="image/png,image/jpeg,image/jpg" id="imgFile" @change="getFile">
        </div>
      </div>
    </div>
    <div class="c-btn-group">
      <el-button type="info" plain @click="cancel">取消</el-button>
      <el-button type="primary" @click="getCropperImg">确定</el-button>
    </div>
  </div>
</template>
代码解析
  1. <div class="c-copper-container" :class="{'wd260' : type == 'articlesubmit'}">

    • 定义了一个容器,并根据 type 属性动态添加 wd260 类。
  2. <div class="c-copper-box">

    • 包含图片裁剪和预览的主要布局。
  3. <div class="c-image-box">

    • 裁剪图片显示区域。
  4. <img :src="copperImgUrl" id="image" alt="暂无图片">

    • 绑定了一个图片标签,用于显示裁剪的图片。
  5. <div class="c-preview-box">

    • 图片预览区域。
  6. <div class="img-preview">

    • 包含预览标题和预览图片。
  7. <el-button icon="cs-format-image" size="mini" plain>上传图片</el-button>

    • 上传图片按钮。
  8. <input type="file" accept="image/png,image/jpeg,image/jpg" id="imgFile" @change="getFile">

    • 文件输入框,监听文件变化事件 getFile
  9. <el-button type="info" plain @click="cancel">取消</el-button>

    • 取消按钮,触发 cancel 方法。
  10. <el-button type="primary" @click="getCropperImg">确定</el-button>

    • 确定按钮,触发 getCropperImg 方法。

JavaScript 部分

<script>
  import { dataURItoBlob } from '@/utils'
  export default {
    name: 'CropperImage',
    data () {
      return {
        copperImgUrl: '', // 被剪裁的图片地址
        option: {
          viewMode: 1, // 裁剪框只能图片内部移动
          dragMode: 'move', // 裁剪框只可以移动,不可以新建
          aspectRatio: 1, // 裁剪框比例
          preview: '.preview', // 预览的dom节点
          checkCrossOrigin: false, // 不检查跨域图像
          movable: false, // 设置图片可不移动
          rotatable: false, // 设置图片不可旋转
          scalable: false, // 设置图片不可缩放
          zoomable: false, // 设置图片不可放大
          zoomOnTouch: false, // 设置图片不可被拖动触摸放大
          toggleDragModeOnDblclick: true, // 点击两次时可以在“crop”和“move”之间切换拖拽模式
          minCropBoxWidth: '5', // 裁剪层最小宽度
          minCropBoxHeight: '5' // 裁剪层最小高度
        }
      }
    },
    props: {
      cropperOption: {
        type: Object,
        default: () => {
          return null
        }
      },
      fileSize: {
        type: Number,
        default: 0.8
      },
      fileType: {
        type: String,
        default: 'jpeg'
      },
      imageFile: {},
      sizeNum:{
        type: Number,
        default: 0
      },
      type:{
        type: String,
        default: ''
      }
    },
    watch: {
      imageFile (file) {
        this.fileHandle(file)
      }
    },
    methods: {
      initCropperModel () {
        if (this.cropperOption) {
          for (let key in this.option) {
            this.option[key] = this.cropperOption[key] || this.option[key]
          }
        }
        let $image = document.getElementById('image')
        this.cropper = new Cropper($image, this.option)
      },
      getFile (e) {
        let file = e.target.files[0]
        let _sizeNum = this.sizeNum
        if(_sizeNum){
          const isLtSize = file.size / 1024 / 1024 < _sizeNum
          if (!isLtSize) {
            this.$message({
              message: this.type == 'articlesubmit' ? `图片大小不能超过 ${_sizeNum}M!` :  `图片大小不能超过 ${_sizeNum * 1000}kb!`,
              type: 'error'
            })
            e.target.value = ''
            return false
          }
        }
        this.fileHandle(file)
      },
      fileHandle (file) {
        if (!file) return 
        if (!window.FileReader) return 
        let vm = this
        let reader = new FileReader()
        reader.readAsDataURL(file)
        reader.onloadend = function () {
          vm.copperImgUrl = this.result
          vm.resetCropperImg()
        }
      },
      resetCropperImg () {
        this.cropper.reset()
        this.cropper.replace(this.copperImgUrl)
      },
      getCropperImg () {
        let canvas = this.cropper.getCroppedCanvas();
        if (this.fileType === 'image/png') {
          let ctx = canvas.getContext('2d');
          ctx.fillStyle = "rgba(0,0,0,0)"; 
          ctx.fillRect(0, 0, canvas.width, canvas.height);
        }
        let newImageData = canvas.toDataURL('image/png');
        let blob = dataURItoBlob(newImageData);
        let formData = new FormData();
        formData.append('icon', blob);
        this.$emit('cropped', newImageData, formData);
      },
      cancel () {
        this.$emit('cancel')
      }
    },
    created () {
      this.fileHandle(this.imageFile)
    },
    mounted () {
      this.initCropperModel()
    },
    beforeDestroy () {
      this.copperImgUrl = ''
      this.cropper.destroy()
    }
  }
</script>
代码解析
  1. data ():

    • 定义组件的数据属性,包括图片URL和裁剪器的配置项。
  2. props:

    • 定义父组件传入的属性,包括裁剪配置、文件大小和类型等。
  3. watch:

    • 监听 imageFile 的变化,当文件变化时调用 fileHandle 方法。
  4. methods:

    • initCropperModel ():初始化 Cropper.js 实例。
    • getFile (e):获取上传的文件并处理。
    • fileHandle (file):处理上传的文件,将文件转换为Base64格式。
    • resetCropperImg ():重置裁剪器的图片。
    • getCropperImg ():获取裁剪后的图片,并将其转换为Blob格式。
    • cancel ():取消操作。
  5. created ()

    • 在组件创建时处理初始图片文件。
  6. mounted ()

    • 在组件挂载时初始化裁剪器。
  7. beforeDestroy ()

    • 在组件销毁前清理裁剪器实例。

样式部分

<style scoped lang="stylus" rel="stylesheet">
  .c-copper-container {
    width 450px
    font-size 12px
    margin-top 20px
    &.wd260{
      width 260px
      .img-upload-btn .el-button{
        padding 7px 5px
      }
      .c-image-box {
        width 188px
        height 188px
        & img {
          max-width 100%
        }
        >>> .cropper-bg{
          width 200px !important
        }
      }
      .c-preview-box {
        width 80px
        .img-preview {
          padding 5px 8px
          height 100px
        }
        .preview {
          width 60px
          height 60px
        }
      }
    }
    .c-copper-box {
      display flex
    }
    .c-image-box {
      width 250px
      height 250px
      margin-right 20px
      background #868686
      & img {
        max-width 100%
      }
    }
    .c-preview-box {
      width 180px
      text-align center
      .img-preview {
        width 100%
        padding 10px 15px
        height 200px
        box-sizing border-box
        border 1px solid #e8e8e8
        background #fafafa
      }
      .title {
        padding-bottom 5px
      }
      .preview {
        width 148px
        height 148px
        overflow hidden
        background-color #fff
        border 1px solid #e8e8e8
        display inline-block
      }
    }
    .img-upload-btn {
      position relative
      margin-top 18px
      &:hover .el-button {
        color #168FCA
        border-color #168FCA
        transition all .1s
      }
      & /deep/ i, & /deep/ span {
        display inline-block
        vertical-align middle
      }
      .el-button {
        width 100%
        border-radius 0
      }
      #imgFile {
        position absolute
        width 100%
        height 100%
        top 0
        left 0
        opacity 0
        cursor pointer
      }
    }
    .c-btn-group {
      padding-top 20px
      text-align center
      .el-button {
        width 100px
      }
    }
  }
</style>
代码解析
  1. 定义了组件的样式,包括容器宽度、字体大小等。

  2. 使用了 scoped 属性,确保样式仅应用于当前组件。

  3. 采用了Stylus语法编写样式,提高了代码的可读性和易维护性。

总结

通过以上代码,我们实现了一个基于Vue.js和Cropper.js的图片裁剪组件,用户可以上传图片并进行裁剪操作,最终获取裁剪后的图片数据。这个组件可以方便地集成到Vue.js应用中,为用户提供了良好的图片处理体验。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值