vue+element上传图片并裁剪(一张)

vue后台上传图片功能,并按一定比例裁剪编辑,确定后可再重新选择图片进行操作,效果如下:

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

直接扔代码:

下载命令:
npm install cropperjs --save-dev

1.父组件中:

 <div>
   <div>文章封面:</div>
   <cutImageDialog @resurl="resurl" />
 </div>
 
import cutImageDialog from '@/components/cutImageDialog'
components: { cutImageDialog },

2.子组件(自己新建一个组件页面,可直接粘贴复制,配置自改)

<template>
  <div id="demo">
    <div v-show="panel" class="father">
      <div class="container">
        <div
          id="cropper"
          style="margin-top:1%;margin-left: 1%;margin-right: 1%;height: 85%;margin-bottom: 1%"
        >
          <img id="image" :src="url" alt="Picture">
        </div>
        <div>
          <div style="float: right;margin-right: 1%">
            <el-button icon="el-icon-zoom-out" size="mini" circle @click="zoom(-1)" />
            <el-button icon="el-icon-zoom-in" size="mini" circle @click="zoom(1)" />
            <el-button icon="el-icon-refresh" size="mini" circle @click="rotate" />
            <el-button type="success" icon="el-icon-check" size="mini" circle @click="crop" />
            <el-button type="danger" icon="el-icon-close" size="mini" circle @click="panel=false" />
          </div>
        </div>
      </div>
    </div>
    <div>
      <div style="margin-top:20px;">
        <input id="change" type="file" accept="image" style="display:none;" @change="change">
        <div
          class="show"
          :style="'backgroundImage:url('+headerImage+');border: 1px dashed '+color"
          @mouseover="addClassload"
          @mouseout="removeClassload"
          @click="upload"
        >
          <i class="el-icon-plus i" :style="'color: '+color" />
        </div>
      </div>
    </div>
  </div>
</template>

<script>
import Cropper from 'cropperjs'
import api from '@/api/conf.js'
export default {
  components: {},
  data() {
    return {
      headerImage: '',
      picValue: '',
      cropper: '',
      croppable: false,
      panel: false,
      url: '',
      color: '#d9d9d9',
      current: 0
    }
  },
  mounted() {
    // 初始化这个裁剪框
    var self = this
    var image = document.getElementById('image')
    this.cropper = new Cropper(image, {
      aspectRatio: 16 / 9, // 裁剪比例
      viewMode: 1,
      zoomOnWheel: false, // 是否允许通过鼠标滚轮来缩放图片
      background: true, // 是否在容器上显示网格背景
      rotatable: true, // 是否允许旋转图片
      ready: function() {
        self.croppable = true
      }
    })
  },
  methods: {
    addClassload() {
      this.color = '#1b95e0'
    },
    removeClassload() {
      this.color = '#d9d9d9'
    },
    // 点击按钮自动执行选择文件事件
    upload() {
      this.url = ''
      this.current = 0
      document.getElementById('change').value = null
      document.getElementById('change').click()
    },
    // 旋转
    rotate() {
      // alert(this.cropper.image)
      this.current = (this.current + 90) % 360
      this.cropper.rotate(this.current)
    },
    // 缩放
    zoom(num) {
      num = num || 1
      this.cropper.zoom(num)
    },

    getObjectURL(file) {
      var url = null
      if (window.createObjectURL !== undefined) {
        // basic
        url = window.createObjectURL(file)
      } else if (window.URL !== undefined) {
        // mozilla(firefox)
        url = window.URL.createObjectURL(file)
      } else if (window.webkitURL !== undefined) {
        // webkit or chrome
        url = window.webkitURL.createObjectURL(file)
      }
      return url
    },
    change(e) {
      console.log(e.target.files[0].size, '图片大小')
      // if (e.target.files[0].size > 500000) {
      //   this.$message.error('图片过大,请重新选择图片')
      //   return
      // } else {
      //   const files = e.target.files || e.dataTransfer.files
      //   if (!files.length) return
      //   this.panel = true
      //   this.picValue = files[0]
      //   this.url = this.getObjectURL(this.picValue)
      //   // 每次替换图片要重新得到新的url
      //   if (this.cropper) {
      //     this.cropper.replace(this.url)
      //   }
      //   // console.log(this.url)
      //   this.panel = true
      // }
      const files = e.target.files || e.dataTransfer.files
      if (!files.length) return
      this.panel = true
      this.picValue = files[0]
      this.url = this.getObjectURL(this.picValue)
      // 每次替换图片要重新得到新的url
      if (this.cropper) {
        this.cropper.replace(this.url)
      }
      // console.log(this.url)
      this.panel = true
    },
    crop() {
      this.panel = false
      var croppedCanvas
      if (!this.croppable) {
        return
      }
      // Crop
      croppedCanvas = this.cropper.getCroppedCanvas()
      // console.log(this.cropper.url, '图片路径')// 图片路径
      // Round
      /* 截取圆形
        roundedCanvas = this.getRoundedCanvas(croppedCanvas);
        this.headerImage = roundedCanvas.toDataURL();
        */
      // 方形
      // croppedCanvas canvas的宽高
      this.headerImage = croppedCanvas.toDataURL('image/jpeg')
      // console.log(this.headerImage, 'this.headerImage')
      // var gettype = Object.prototype.toString
      this.postImg()
    },
    dataURLtoFile(dataurl, filename = 'file') {
      const arr = dataurl.split(',')
      const mime = arr[0].match(/:(.*?);/)[1]
      const suffix = mime.split('/')[1]
      const bstr = atob(arr[1])
      let n = bstr.length
      const u8arr = new Uint8Array(n)
      while (n--) {
        u8arr[n] = bstr.charCodeAt(n)
      }
      return new File([u8arr], `${filename}.${suffix}`, { type: mime })
    },
    /* // 截取圆形
      getRoundedCanvas (sourceCanvas) {
        var canvas = document.createElement('canvas');
        var context = canvas.getContext('2d');
        var width = sourceCanvas.width;
        var height = sourceCanvas.height;
        canvas.width = width;
        canvas.height = height;
        context.imageSmoothingEnabled = true;
        context.drawImage(sourceCanvas, 0, 0, width, height);
        context.globalCompositeOperation = 'destination-in';
        context.beginPath();
        context.arc(width / 2, height / 2, Math.min(width, height) / 2, 0, 2 * Math.PI, true);
        context.fill();
        return canvas;
      },*/
    postImg() {
      // 图片的上传
      var formData = new FormData()
      formData.append('file', this.dataURLtoFile(this.headerImage))
      console.log(this.headerImage, 'this.headerImage')
      //上传到服务器接口
      api.upload(formData).then(res => {
        if (res.data.meta.code === 200) {
          this.$message.success('上传成功')
          console.log(res.data.data.url)
          this.resurl = res.data.data.url
          this.$emit('resurl', this.resurl)//因为我的信息提交在父组件,所以事件发射给父
        } else {
          this.$message.error('请重新选择图片')
        }
      })
    }
  }
}
</script>

<style>
* {
  margin: 0;
  padding: 0;
}

.father {
  background-color: rgba(0, 0, 0, 0.5);
  position: fixed;
  left: 0px;
  top: 0px;
  width: 100%;
  height: 100%;
  z-index: 999999;
}
.i {
  font-size: 28px;
  color: #8c939d;
  width: 100px;
  height: 100px;
  line-height: 100px;
  text-align: center;
}
#demo .show {
  border: 1px dashed #d9d9d9;
  border-radius: 10%;
  width: 100px;
  height: 100px;
  cursor: pointer;
  position: relative;
  overflow: hidden;
  display: inline-block;
  text-align: center;
  outline: none;
  background-position: center center;
  background-repeat: no-repeat;
  background-size: cover;
}
#demo .container {
  z-index: 99;
  height: 400px;
  width: 600px;
  position: fixed;
  /*padding-top: 60px;*/
  left: 30%;
  top: 20%;

  background-color: white;
}
#demo #image {
  max-width: 100%;
}
/* .cropper-view-box,.cropper-face {
    border-radius: 100%; 圆形截图设置
  }*/
/*!
   * Cropper.js v1.0.0-rc
   * https://github.com/fengyuanchen/cropperjs
   *
   * Copyright (c) 2017 Fengyuan Chen
   * Released under the MIT license
   *
   * Date: 2017-03-25T12:02:21.062Z
   */
.cropper-container {
  font-size: 0;
  line-height: 0;
  position: relative;
  -webkit-user-select: none;
  -moz-user-select: none;
  -ms-user-select: none;
  user-select: none;
  direction: ltr;
  -ms-touch-action: none;
  touch-action: none;
}

.cropper-container img {
  /* Avoid margin top issue (Occur only when margin-top <= -height) */
  display: block;
  min-width: 0 !important;
  max-width: none !important;
  min-height: 0 !important;
  max-height: none !important;
  width: 100%;
  height: 100%;
  image-orientation: 0deg;
}
.cropper-wrap-box,
.cropper-canvas,
.cropper-drag-box,
.cropper-crop-box,
.cropper-modal {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
}
.cropper-wrap-box {
  overflow: hidden;
}
.cropper-drag-box {
  opacity: 0;
  background-color: #fff;
}
.cropper-modal {
  opacity: 0.5;
  background-color: #000;
}
.cropper-view-box {
  display: block;
  overflow: hidden;
  width: 100%;
  height: 100%;
  outline: 1px solid #39f;
  outline-color: rgba(51, 153, 255, 0.75);
}

.cropper-dashed {
  position: absolute;
  display: block;
  opacity: 0.5;
  border: 0 dashed #eee;
}
.cropper-dashed.dashed-h {
  top: 33.33333%;
  left: 0;
  width: 100%;
  height: 33.33333%;
  border-top-width: 1px;
  border-bottom-width: 1px;
}
.cropper-dashed.dashed-v {
  top: 0;
  left: 33.33333%;
  width: 33.33333%;
  height: 100%;
  border-right-width: 1px;
  border-left-width: 1px;
}
.cropper-center {
  position: absolute;
  top: 50%;
  left: 50%;
  display: block;
  width: 0;
  height: 0;
  opacity: 0.75;
}
.cropper-center:before,
.cropper-center:after {
  position: absolute;
  display: block;
  content: " ";
  background-color: #eee;
}
.cropper-center:before {
  top: 0;
  left: -3px;
  width: 7px;
  height: 1px;
}
.cropper-center:after {
  top: -3px;
  left: 0;
  width: 1px;
  height: 7px;
}
.cropper-face,
.cropper-line,
.cropper-point {
  position: absolute;
  display: block;
  width: 100%;
  height: 100%;
  opacity: 0.1;
}
.cropper-face {
  top: 0;
  left: 0;
  background-color: #fff;
}
.cropper-line {
  background-color: #39f;
}
.cropper-line.line-e {
  top: 0;
  right: -3px;
  width: 5px;
  cursor: e-resize;
}
.cropper-line.line-n {
  top: -3px;
  left: 0;
  height: 5px;
  cursor: n-resize;
}
.cropper-line.line-w {
  top: 0;
  left: -3px;
  width: 5px;
  cursor: w-resize;
}
.cropper-line.line-s {
  bottom: -3px;
  left: 0;
  height: 5px;
  cursor: s-resize;
}
.cropper-point {
  width: 5px;
  height: 5px;

  opacity: 0.75;
  background-color: #39f;
}
.cropper-point.point-e {
  top: 50%;
  right: -3px;
  margin-top: -3px;
  cursor: e-resize;
}
.cropper-point.point-n {
  top: -3px;
  left: 50%;
  margin-left: -3px;
  cursor: n-resize;
}
.cropper-point.point-w {
  top: 50%;
  left: -3px;
  margin-top: -3px;
  cursor: w-resize;
}
.cropper-point.point-s {
  bottom: -3px;
  left: 50%;
  margin-left: -3px;
  cursor: s-resize;
}
.cropper-point.point-ne {
  top: -3px;
  right: -3px;
  cursor: ne-resize;
}
.cropper-point.point-nw {
  top: -3px;
  left: -3px;
  cursor: nw-resize;
}
.cropper-point.point-sw {
  bottom: -3px;
  left: -3px;
  cursor: sw-resize;
}
.cropper-point.point-se {
  right: -3px;
  bottom: -3px;
  width: 20px;
  height: 20px;
  cursor: se-resize;
  opacity: 1;
}
@media (min-width: 768px) {
  .cropper-point.point-se {
    width: 15px;
    height: 15px;
  }
}
@media (min-width: 992px) {
  .cropper-point.point-se {
    width: 10px;
    height: 10px;
  }
}
@media (min-width: 1200px) {
  .cropper-point.point-se {
    width: 5px;
    height: 5px;
    opacity: 0.75;
  }
}
.cropper-point.point-se:before {
  position: absolute;
  right: -50%;
  bottom: -50%;
  display: block;
  width: 200%;
  height: 200%;
  content: " ";
  opacity: 0;
  background-color: #39f;
}
.cropper-invisible {
  opacity: 0;
}
.cropper-bg {
  background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAAA3NCSVQICAjb4U/gAAAABlBMVEXMzMzTjRV2AAAACXBIWXMAAArrAAAK6wGCiw1aAAAAHHRFWHRTb2Z0d2FyZQBBZG9iZSBGaXJld29ya3MgQ1M26LyyjAAAABFJREFUCJlj+M/AgBVhF/0PAH6/D/HkDxOGAAAAAElFTkSuQmCC");
}
.cropper-hide {
  position: absolute;
  display: block;
  width: 0;
  height: 0;
}
.cropper-hidden {
  display: none !important;
}
.cropper-move {
  cursor: move;
}
.cropper-crop {
  cursor: crosshair;
}
.cropper-disabled .cropper-drag-box,
.cropper-disabled .cropper-face,
.cropper-disabled .cropper-line,
.cropper-disabled .cropper-point {
  cursor: not-allowed;
}
</style>

这篇是我封装的组件,原文请参考:https://blog.csdn.net/qq_41389920/article/details/87968408

好的,针对您的问题,以下是实现 Vue+Element-UI上传图片并压缩的基本步骤: 1. 安装依赖 在项目中安装 Element-UI 和插件 vue-image-crop-upload 以及图片压缩库,可使用以下命令: ``` npm install element-ui vue-image-crop-upload compressjs --save ``` 2. 引入 Element-UI 在 main.js 中引入 Element-UI: ```javascript import Vue from 'vue' import ElementUI from 'element-ui' import 'element-ui/lib/theme-chalk/index.css' Vue.use(ElementUI) ``` 3. 使用 vue-image-crop-upload 在需要上传图片的组件中使用 vue-image-crop-upload,可使用以下代码: ```vue <template> <div> <vue-image-crop-upload ref="upload" :url="uploadUrl" :headers="uploadHeaders" :size="size" :accept="accept" :beforeUpload="beforeUpload" :cropConfig="cropConfig" :compressConfig="compressConfig" @input="handleInput" @crop-success="handleCropSuccess" > <el-button size="small" type="primary">上传图片</el-button> </vue-image-crop-upload> </div> </template> <script> import VueImageCropUpload from 'vue-image-crop-upload' export default { components: { VueImageCropUpload }, data() { return { uploadUrl: 'xxx', // 上传地址 uploadHeaders: { // 上传请求头 Authorization: 'Bearer ' + getToken() }, size: 1024 * 1024 * 2, // 上传图片大小限制 accept: '.jpg,.jpeg,.png', // 上传图片格式限制 cropConfig: { // 图片裁剪配置 aspectRatio: 1 / 1, autoCropArea: 1, viewMode: 1, zoomable: false, guides: false, dragMode: 'move', cropBoxResizable: false, crop: () => {} }, compressConfig: { // 图片压缩配置 targetSize: 1024 * 1024, // 目标大小 quality: 0.7, // 压缩质量 mimeType: 'image/jpeg' // 输出格式 } } }, methods: { beforeUpload(file) { // 文件上传前的回调函数 this.$refs.upload.startUpload() }, handleInput(file) { // 文件选择后的回调函数 this.$refs.upload.showCrop() }, handleCropSuccess(blob, file) { // 图片裁剪成功后的回调函数 this.compressImage(blob, file) // 压缩图片 }, compressImage(blob, file) { // 图片压缩 const reader = new FileReader() reader.readAsDataURL(blob) reader.onload = (e) => { const base64 = e.target.result const compressedBlob = Compress.compress(base64, this.compressConfig) const compressedFile = new File([compressedBlob], file.name, { type: compressedBlob.type }) this.$emit('upload', compressedFile) // 触发上传事件 } } } } </script> ``` 4. 完成上传 在父组件中监听上传事件,使用 axios 或其他方法上传文件至服务器: ```vue <template> <div> <upload :action="uploadUrl" @upload="handleUpload"></upload> </div> </template> <script> import axios from 'axios' import Upload from './Upload.vue' export default { components: { Upload }, data() { return { uploadUrl: 'xxx' // 上传地址 } }, methods: { handleUpload(file) { const formData = new FormData() formData.append('file', file) axios.post(this.uploadUrl, formData).then(response => { console.log(response.data) }) } } } </script> ``` 以上就是实现 Vue+Element-UI上传图片并压缩的基本步骤,您可以根据您的具体需求进行修改和优化。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

咸鱼起码是条鱼

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值