<!-- 这个图片剪裁插件,兼容ios与安卓 --><template><div class="vue-box"><img :src="imgUrl" alt="" id="img"><input type="file" class="file" accept="image/png,image/jpg,image/jpeg" @change="change($event)"></div>
</template>
<script>
import Cropper from 'cropperjs'
import Exif from 'exif-js'
export default {props: {// 定义的宽高比widthRate: {type: Number,default: 1,},// 定义的宽高比heightRate: {type: Number,default: 1},imgUrl: {type: String,default: function() {return ''}}},data() {return {}},methods: {change(event) {let image = document.getElementById('img'); //预览对象this.clip(event, {resultObj: image,aspectWithRatio: Number(this.widthRate),aspectHeightRatio: Number(this.heightRate)})},//初始化方法initilize(opt) {let self = this;this.options = opt;//创建domthis.createElement();this.resultObj = opt.resultObj;//初始化裁剪对象this.cropper = new Cropper(this.preview, {aspectRatio: opt.aspectWithRatio / opt.aspectHeightRatio,// aspectRatio: 1/1,autoCropArea: opt.autoCropArea || 0.8,viewMode: 2,guides: true,cropBoxResizable: true, //是否通过拖动来调整剪裁框的大小cropBoxMovable: true, //是否通过拖拽来移动剪裁框。dragCrop: false,dragMode: "move",//‘crop’: 可以产生一个新的裁剪框3 ‘move’: 只可以移动3 ‘none’: 什么也不处理center: true,zoomable: true, //是否允许放大图像。zoomOnTouch: true,//是否可以通过拖动触摸来放大图像。scalable: true,// minCropBoxHeight: 750,// minCropBoxWidth: 750,background: false,checkOrientation: true,checkCrossOrigin: true,zoomable: false,zoomOnWheel: false,center: false,toggleDragModeOnDblclick: false,ready: function() {// console.log(self.cropper.rotate(90))if (opt.aspectRatio == 'Free') {let cropBox = self.cropper.cropBox;cropBox.querySelector('span.cropper-view-box').style.outline = 'none';self.cropper.disable();}}});},//创建一些必要的DOM,用于图片裁剪createElement() {//初始化图片为空对象this.preview = null;// <img src="../../assets/app/loading.gif">let str = '<div><img id="clip_image" src="originUrl"></div><button type="button" id="cancel_clip">取消</button><button type="button" id="clip_button">确定</button>';str += '<div class="crop_loading"><div class="crop_content"><div class="crop_text">图片修剪中...</div></div></div>';str += '<div class="crop_success"><div class="crop_success_text">上传成功</div></div></div>';let body = document.getElementsByTagName('body')[0];this.reagion = document.createElement('div');this.reagion.id = 'clip_container';this.reagion.className = 'container';this.reagion.innerHTML = str;//添加创建好的DOM元素body.appendChild(this.reagion);this.preview = document.getElementById('clip_image');//绑定一些方法this.initFunction();},//初始化一些函数绑定initFunction() {let self = this;this.clickBtn = document.getElementById('clip_button');this.cancelBtn = document.getElementById('cancel_clip');//确定事件this.addEvent(this.clickBtn, 'click', function() {self.crop();})//取消事件this.addEvent(this.cancelBtn, 'click', function() {self.destoried();})//清空input的值this.addEvent(this.fileObj, 'click', function() {this.value = '';})},//外部接口,用于input['file']对象change时的调用clip(e, opt) {let self = this;this.fileObj = e.srcElement;let files = e.target.files || e.dataTransfer.files;if (!files.length) return false; //不是图片直接返回//调用初始化方法this.initilize(opt);//获取图片文件资源this.picValue = files[0];//去获取拍照时的信息,解决拍出来的照片旋转问题// Exif.getData( files[0] , function(){//   self.Orientation = Exif.getTag( files[0], 'Orientation');//   console.log(self.Orientation)// });//调用方法转成url格式this.originUrl = this.getObjectURL(this.picValue);//每次替换图片要重新得到新的urlif (this.cropper) {this.cropper.replace(this.originUrl);}},//图片转码方法getObjectURL(file) {let url = null;if (window.createObjectURL != undefined) { // basicurl = window.createObjectURL(file);} else if (window.URL != undefined) { // mozilla(firefox)url = window.URL.createObjectURL(file);} else if (window.webkitURL != undefined) { // webkit or chromeurl = window.webkitURL.createObjectURL(file);}return url;},//点击确定进行裁剪crop() {let self = this;let image = new Image();let croppedCanvas;let roundedCanvas;// Cropdocument.querySelector('.crop_loading').style.display = 'block';setTimeout(function() {croppedCanvas = self.cropper.getCroppedCanvas();// RoundroundedCanvas = self.getRoundedCanvas(croppedCanvas);let imgData = roundedCanvas.toDataURL();image.src = imgData;//判断图片是否大于100k,不大于直接上传,反之压缩if (imgData.length < (100 * 1024)) {self.resultObj.src = imgData;//图片上传self.postImg(imgData);} else {image.onload = function() {//压缩处理let data = self.compress(image, self.Orientation);self.resultObj.src = data;//图片上传self.postImg(data);}}}, 20)},//获取裁剪图片资源getRoundedCanvas(sourceCanvas) {let canvas = document.createElement('canvas');let context = canvas.getContext('2d');let width = sourceCanvas.width;let 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.rect(0, 0, width, height);context.fill();return canvas;},//销毁原来的对象destoried() {let self = this;//移除事件this.removeEvent(this.clickBtn, 'click', null);this.removeEvent(this.cancelBtn, 'click', null);this.removeEvent(this.fileObj, 'click', null);//移除裁剪框this.reagion.parentNode.removeChild(this.reagion);//销毁裁剪对象this.cropper.destroy();this.cropper = null;},//图片上传postImg(imageData) {// console.log(imageData)this.$emit('callback', imageData)//这边写图片的上传let self = this;self.destoried();// window.setTimeout( function () {//   document.querySelector('.crop_loading').style.display = 'none';//   document.querySelector('.crop_success').style.display = 'block';//   //裁剪完后摧毁对象//     self.destoried();// },3000)},//图片旋转rotateImg(img, direction, canvas) {//最小与最大旋转方向,图片旋转4次后回到原方向const min_step = 0;const max_step = 3;if (img == null) return;//img的高度和宽度不能在img元素隐藏后获取,否则会出错let height = img.height;let width = img.width;let step = 2;if (step == null) {step = min_step;}if (direction == 'right') {step++;//旋转到原位置,即超过最大值step > max_step && (step = min_step);} else {step--;step < min_step && (step = max_step);}//旋转角度以弧度值为参数let degree = step * 90 * Math.PI / 180;let ctx = canvas.getContext('2d');switch (step) {case 0:canvas.width = width;canvas.height = height;ctx.drawImage(img, 0, 0);break;case 1:canvas.width = height;canvas.height = width;ctx.rotate(degree);ctx.drawImage(img, 0, -height);break;case 2:canvas.width = width;canvas.height = height;ctx.rotate(degree);ctx.drawImage(img, -width, -height);break;case 3:canvas.width = height;canvas.height = width;ctx.rotate(degree);ctx.drawImage(img, -width, 0);break;}},//图片压缩compress(img, Orientation) {let canvas = document.createElement("canvas");let ctx = canvas.getContext('2d');//瓦片canvaslet tCanvas = document.createElement("canvas");let tctx = tCanvas.getContext("2d");let initSize = img.src.length;let width = img.width;let height = img.height;//如果图片大于四百万像素,计算压缩比并将大小压至400万以下let ratio;if ((ratio = width * height / 4000000) > 1) {console.log("大于400万像素")ratio = Math.sqrt(ratio);width /= ratio;height /= ratio;} else {ratio = 1;}canvas.width = width;canvas.height = height;//        铺底色ctx.fillStyle = "#fff";ctx.fillRect(0, 0, canvas.width, canvas.height);//如果图片像素大于100万则使用瓦片绘制let count;if ((count = width * height / 1000000) > 1) {count = ~~(Math.sqrt(count) + 1); //计算要分成多少块瓦片//            计算每块瓦片的宽和高let nw = ~~(width / count);let nh = ~~(height / count);tCanvas.width = nw;tCanvas.height = nh;for (let i = 0; i < count; i++) {for (let j = 0; j < count; j++) {tctx.drawImage(img, i * nw * ratio, j * nh * ratio, nw * ratio, nh * ratio, 0, 0, nw, nh);ctx.drawImage(tCanvas, i * nw, j * nh, nw, nh);}}} else {ctx.drawImage(img, 0, 0, width, height);}//修复ios上传图片的时候 被旋转的问题if (Orientation != "" && Orientation != 1) {switch (Orientation) {case 6: //需要顺时针(向左)90度旋转this.rotateImg(img, 'left', canvas);break;case 8: //需要逆时针(向右)90度旋转this.rotateImg(img, 'right', canvas);break;case 3: //需要180度旋转this.rotateImg(img, 'right', canvas); //转两次this.rotateImg(img, 'right', canvas);break;}}//进行最小压缩// let ndata = canvas.toDataURL( 'image/jpeg' , 0.1);let ndata = canvas.toDataURL('image/png', 0.1);console.log('压缩前:' + initSize);console.log('压缩后:' + ndata.length);console.log('压缩率:' + ~~(100 * (initSize - ndata.length) / initSize) + "%");tCanvas.width = tCanvas.height = canvas.width = canvas.height = 0;return ndata;},//添加事件addEvent(obj, type, fn) {if (obj.addEventListener) {obj.addEventListener(type, fn, false);} else {obj.attachEvent('on' + type, fn);}},//移除事件removeEvent(obj, type, fn) {if (obj.removeEventListener) {obj.removeEventListener(type, fn, false);} else {obj.detachEvent('on' + type, fn);}},}
}
</script>
<style scoped>
.vue-box {position: relative;width: 100%;height: 100%;min-height: 0.4rem;
}.vue-box .file {position: absolute;width: 100%;height: 100%;opacity: 0;top: 0;left: 0;z-index: 99;cursor: pointer;
}img {display: none;width: 100%;height: 100%;
}h3 {text-align: center;
}h1,
h2 {font-weight: normal;
}ul {list-style-type: none;padding: 0;
}li {display: inline-block;margin: 0 10px;
}a {color: #42b983;
}
</style>
<style>
#app {font-family: 'Avenir', Helvetica, Arial, sans-serif;-webkit-font-smoothing: antialiased;-moz-osx-font-smoothing: grayscale;text-align: center;color: #2c3e50;margin-top: 60px;
}* {margin: 0;padding: 0;
}#app {font-family: 'Avenir', Helvetica, Arial, sans-serif;-webkit-font-smoothing: antialiased;-moz-osx-font-smoothing: grayscale;box-sizing: border-box;
}img {/*display: block;*//*margin: 0 auto;*/
}input[type='file'] {outline: none;/*margin-top: 20px;*/
}* {margin: 0;padding: 0;
}#clip_button {position: absolute;right: 10%;bottom: 20px;width: 80px;height: 40px;border: none;border-radius: 2px;background: #1AAD19;color: #fff;
}#cancel_clip {position: absolute;left: 10%;bottom: 20px;width: 80px;height: 40px;border: none;border-radius: 2px;color: #fff;background: #E64340;
}#clip_container.container {z-index: 99999;position: fixed;padding-top: 60px;left: 0;top: 0;right: 0;bottom: 0;background: rgba(0, 0, 0, 1);
}#clip_container.container>div {position: absolute;width: 100%;height: 100%;top: 50%;left: 50%;-webkit-transform: translate(-50%, -50%);transform: translate(-50%, -50%);
}#clip_image {max-width: 100%;
}.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
}.crop_loading,
.crop_success {display: none;position: fixed;top: 0;left: 0;width: 100%;height: 100%;z-index: 9;
}.crop_loading .crop_content {position: absolute;top: 50%;left: 50%;text-align: center;background: #000;opacity: 0.9;height: 66px;width: 140px;vertical-align: middle;color: #fff;padding-top: 20px;font-size: 16px;-webkit-border-radius: 3px;border-radius: 3px;-webkit-transform: translate(-50%, -50%);transform: translate(-50%, -50%);
}.crop_loading .crop_content img {margin-top: 15px;margin-bottom: 10px;
}.crop_success .crop_success_text {position: absolute;top: 50%;left: 50%;text-align: center;background: #000;opacity: 0.9;width: 120px;height: 30px;color: #fff;line-height: 30px;font-size: 16px;-webkit-border-radius: 3px;border-radius: 3px;-webkit-transform: translate(-50%, -50%);transform: translate(-50%, -50%);
}.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: .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: .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: .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: .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: .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: .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>

vue 图片裁剪压缩相关推荐

  1. VUE图片裁剪功能vue-img-cutter

    VUE图片裁剪功能vue-img-cutter 前言: 演示地址 兼容IE9+,MSEdge,Chrome,Firefox 两种展现形式,行内或弹窗 可旋转.缩放图片 任意比例.大小裁剪 固定比例.大 ...

  2. VUE图片裁剪组件,基于VueCropper

    VUE图片裁剪组件,基于VueCropper 搬砖的同志麻烦点个赞支持下 效果图 第一步安装vue-cropper插件 npm install vue-cropper 第二步创建组件,把下面的代码复制 ...

  3. vue图片裁剪组件_使用Vue-Rx的Vue.js图像裁剪组件

    vue图片裁剪组件 Vuejs夹 (vuejs-clipper) Vue.js image clipping components using Vue-Rx. 使用Vue-Rx的Vue.js图像裁剪组 ...

  4. vue图片裁剪组件_Vue.js图像裁剪组件

    vue图片裁剪组件 Vuejs夹 (vuejs-clipper) Vue.js image clipping components using Vue-Rx. 使用Vue-Rx的Vue.js图像裁剪组 ...

  5. ie js html 压缩,H5图片裁剪-压缩-上传-神奇的Croppie.js

    Croppie.js之图片裁剪压缩上传 h5图片裁剪, 压缩, 上传, 预览是常见功能, 幸运的是我们有cropp.js这款利器. 1. style .actions button, .actions ...

  6. vue 移动端头像裁剪_基于vue的移动端图片裁剪压缩处理

    前端时间做Vue项目的时候,要用到图片压缩处理,网上查阅了资料后,发现并不能满足实际的业务需求:于是,自己结合网上的资料写了一个,有兴趣的小伙伴不妨试试~ 废话不多说,先上效果图,无图无真相嘛~ 效果 ...

  7. Java实现批量压缩图片 裁剪压缩多种尺寸缩略图 一键批量上传图片

    10万+IT人都在关注的图片批量压缩上传方案(完整案例+代码) 背景需求:为了客户端访问图片资源时,加载图片更流畅,体验更好,通常不会直接用原图路径,需要根据不同的场景显示不同规格的缩略图,根据商品关 ...

  8. vue 图片裁剪上传

    最近写的一个项目用到头像上传,需要裁剪功能,缩放功能,能具备压缩上传功能,因为手机现在的像素太好了,随便一张图片的大小都上M了,而且要求手机端和pc端都可要可以使用.通过网上找到了一个合适的插件(vu ...

  9. vue+图片裁剪vue-cropper以及api

    前言: 因为项目需要,需要实现一个上传完图片,对图片进行二次处理的需求,就使用了vue-cropper来实现这个功能,总的来说还是感觉非常不错的软件,这里分享下我的使用方法,以及vue-cropper ...

最新文章

  1. 如何更改已生成的APK的APP名字?
  2. python莱布尼茨法计算π_酷叮猫少儿编程讲堂——Python 用莱布尼茨等式求π
  3. scala入门-05继承类(extends)的使用
  4. freeradius的proxy功能
  5. 八皇后问题详解(最短代码)
  6. python后端需要什么基础_【后端开发】python爬虫需要什么基础
  7. linux吉祥物的名字,知道Linux的吉祥物的名字和性别吗
  8. python 3.5安装pywin32
  9. sts 明明导包正确却报错_这真是危险的关系,明明你错了,但是她认了!
  10. VSCode REMOTE SSH
  11. sqlserver 建表指定主键_3-自增字段;主键约束
  12. Microsoft Data Access Components(MDAC) 结构以及一些连接SQL数据库的架构基础
  13. html之圆形用户头像
  14. PMP项目管理—项目风险管理(7)
  15. hdu5510Bazinga
  16. 使用conda安装pytorch时出现问题CondaSSLError: OpenSSL appears to be unavailable on this machine.
  17. python如何编写温度转换_Python温度转换实例分析
  18. Ubuntu搭建EDK2环境
  19. Simscape/Simulink 电力仿真降压电路 Buck Converter
  20. 上海某外企网络工程师面试题「含答案」

热门文章

  1. 【流式计算】twitter storm Rationale[1]
  2. 最新简易商城小程序源码+易优CMS后台内核
  3. Bounding box(bbox) 预测
  4. 【前端】ext formulas data method
  5. 怎么把电子版照片换底色?照片换底色最简单的方法
  6. 三星未来系统显示服务器进水了,三星GALAXY S8+进水二修不开机,CPU烧坏要保资料?这都能完美搞定...
  7. 转自http://www.eaw.com.cn/news/display/article/10303有5402方面的文章 (对本人学习C有帮助!)
  8. matlab等于本身是什么命令,matlab中的m=size是什么意思
  9. 中通科技代码覆盖率应用实践(一)
  10. 寂静之地百度云在线观看迅雷下载A Quiet Place高清BT下载