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>
代码解析
    • 定义了一个容器,并根据 type 属性动态添加 wd260 类。
    • 包含图片裁剪和预览的主要布局。
    • 裁剪图片显示区域。
  1. 暂无图片

    • 绑定了一个图片标签,用于显示裁剪的图片。
    • 图片预览区域。
    • 包含预览标题和预览图片。
  2. 上传图片

    • 上传图片按钮。
    • 文件输入框,监听文件变化事件 getFile
  3. 取消

    • 取消按钮,触发 cancel 方法。
  4. 确定

    • 确定按钮,触发 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 ()

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

样式部分


代码解析
  1. 定义了组件的样式,包括容器宽度、字体大小等。

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

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

总结

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

你可能感兴趣的:(vue.js,前端,javascript)