<template> <div class="vue-cropper" ref="cropper" @mouseover="scaleImg" @mouseout="cancelScale"> <div class="cropper-box" v-if="imgs"> <div class="cropper-box-canvas" v-show="!loading" :style="{ 'width': trueWidth + 'px', 'height': trueHeight + 'px', 'transform': 'scale(' + scale + ',' + scale + ') ' + 'translate3d('+ x / scale + 'px,' + y / scale + 'px,' + '0)' + 'rotateZ('+ rotate * 90 +'deg)' }" > <img :src="imgs" alt="cropper-img" ref="cropperImg"> </div> </div> <div class="cropper-drag-box" :class="{'cropper-move': move && !crop, 'cropper-crop': crop, 'cropper-modal': cropping}" @mousedown="startMove" @touchstart="startMove" ></div> <div v-show="cropping" class="cropper-crop-box" :style="{ 'width': cropW + 'px', 'height': cropH + 'px', 'transform': 'translate3d('+ cropOffsertX + 'px,' + cropOffsertY + 'px,' + '0)' }" > <span class="cropper-view-box"> <img :style="{ 'width': trueWidth + 'px', 'height': trueHeight + 'px', 'transform': 'scale(' + scale + ',' + scale + ') ' + 'translate3d('+ (x - cropOffsertX) / scale + 'px,' + (y - cropOffsertY) / scale + 'px,' + '0)' + 'rotateZ('+ rotate * 90 +'deg)' }" :src="imgs" alt="cropper-img" > </span> <span class="cropper-face cropper-move" @mousedown="cropMove" @touchstart="cropMove"></span> <span class="crop-info" v-if="info" :style="{'top': cropInfo.top}" >{{ cropInfo.width }} 脳 {{ cropInfo.height }}</span> <span v-if="!fixedBox"> <span class="crop-line line-w" @mousedown="changeCropSize($event, false, true, 0, 1)" @touchstart="changeCropSize($event, false, true, 0, 1)" ></span> <span class="crop-line line-a" @mousedown="changeCropSize($event, true, false, 1, 0)" @touchstart="changeCropSize($event, true, false, 1, 0)" ></span> <span class="crop-line line-s" @mousedown="changeCropSize($event, false, true, 0, 2)" @touchstart="changeCropSize($event, false, true, 0, 2)" ></span> <span class="crop-line line-d" @mousedown="changeCropSize($event, true, false, 2, 0)" @touchstart="changeCropSize($event, true, false, 2, 0)" ></span> <span class="crop-point point1" @mousedown="changeCropSize($event, true, true, 1, 1)" @touchstart="changeCropSize($event, true, true, 1, 1)" ></span> <span class="crop-point point2" @mousedown="changeCropSize($event, false, true, 0, 1)" @touchstart="changeCropSize($event, false, true, 0, 1)" ></span> <span class="crop-point point3" @mousedown="changeCropSize($event, true, true, 2, 1)" @touchstart="changeCropSize($event, true, true, 2, 1)" ></span> <span class="crop-point point4" @mousedown="changeCropSize($event, true, false, 1, 0)" @touchstart="changeCropSize($event, true, false, 1, 0)" ></span> <span class="crop-point point5" @mousedown="changeCropSize($event, true, false, 2, 0)" @touchstart="changeCropSize($event, true, false, 2, 0)" ></span> <span class="crop-point point6" @mousedown="changeCropSize($event, true, true, 1, 2)" @touchstart="changeCropSize($event, true, true, 1, 2)" ></span> <span class="crop-point point7" @mousedown="changeCropSize($event, false, true, 0, 2)" @touchstart="changeCropSize($event, false, true, 0, 2)" ></span> <span class="crop-point point8" @mousedown="changeCropSize($event, true, true, 2, 2)" @touchstart="changeCropSize($event, true, true, 2, 2)" ></span> </span> </div> </div> </template> <script> import { defineComponent } from 'vue' import exifmin from "./exif-js-min"; export default defineComponent({ data: function() { return { // 瀹瑰櫒楂樺 w: 0, h: 0, // 鍥剧墖缂╂斁姣斾緥 scale: 1, // 鍥剧墖鍋忕Щx杞� x: 0, // 鍥剧墖鍋忕Щy杞� y: 0, // 鍥剧墖鍔犺浇 loading: true, // 鍥剧墖鐪熷疄瀹藉害 trueWidth: 0, // 鍥剧墖鐪熷疄楂樺害 trueHeight: 0, move: true, // 绉诲姩鐨剎 moveX: 0, // 绉诲姩鐨剏 moveY: 0, // 寮€鍚埅鍥� crop: false, // 姝e湪鎴浘 cropping: false, // 瑁佸壀妗嗗ぇ灏� cropW: 0, cropH: 0, cropOldW: 0, cropOldH: 0, // 鍒ゆ柇鏄惁鑳藉鏀瑰彉 canChangeX: false, canChangeY: false, // 鏀瑰彉鐨勫熀鍑嗙偣 changeCropTypeX: 1, changeCropTypeY: 1, // 瑁佸壀妗嗙殑鍧愭爣杞� cropX: 0, cropY: 0, cropChangeX: 0, cropChangeY: 0, cropOffsertX: 0, cropOffsertY: 0, // 鏀寔鐨勬粴鍔ㄤ簨浠� support: "", // 绉诲姩绔墜鎸囩缉鏀� touches: [], touchNow: false, // 鍥剧墖鏃嬭浆 rotate: 0, isIos: false, orientation: 0, imgs: "", // 鍥剧墖缂╂斁绯绘暟 coe: 0.2, // 鏄惁姝e湪澶氭缂╂斁 scaling: false, scalingSet: "", coeStatus: "", // 鎺у埗emit瑙﹀彂棰戠巼 isCanShow: true }; }, props: { img: { type: [String, Blob, null, File], default: "" }, // 杈撳嚭鍥剧墖鍘嬬缉姣� outputSize: { type: Number, default: 1 }, outputType: { type: String, default: "jpeg" }, info: { type: Boolean, default: true }, // 鏄惁寮€鍚粴杞斁澶х缉灏� canScale: { type: Boolean, default: true }, // 鏄惁鑷垚鎴浘妗� autoCrop: { type: Boolean, default: false }, autoCropWidth: { type: [Number, String], default: 0 }, autoCropHeight: { type: [Number, String], default: 0 }, // 鏄惁寮€鍚浐瀹氬楂樻瘮 fixed: { type: Boolean, default: false }, // 瀹介珮姣� w/h fixedNumber: { type: Array, default: () => { return [1, 1]; } }, // 鍥哄畾澶у皬 绂佹鏀瑰彉鎴浘妗嗗ぇ灏� fixedBox: { type: Boolean, default: false }, // 杈撳嚭鎴浘鏄惁缂╂斁 full: { type: Boolean, default: false }, // 鏄惁鍙互鎷栧姩鍥剧墖 canMove: { type: Boolean, default: true }, // 鏄惁鍙互鎷栧姩鎴浘妗� canMoveBox: { type: Boolean, default: true }, // 涓婁紶鍥剧墖鎸夌収鍘熷姣斾緥鏄剧ず original: { type: Boolean, default: false }, // 鎴浘妗嗚兘鍚﹁秴杩囧浘鐗� centerBox: { type: Boolean, default: false }, // 鏄惁鏍规嵁dpr杈撳嚭楂樻竻鍥剧墖 high: { type: Boolean, default: true }, // 鎴浘妗嗗睍绀哄楂樼被鍨� infoTrue: { type: Boolean, default: false }, // 鍙互鍘嬬缉鍥剧墖瀹介珮 榛樿涓嶈秴杩�200 maxImgSize: { type: [Number, String], default: 2000 }, // 鍊嶆暟 鍙覆鏌撳綋鍓嶆埅鍥炬鐨刵鍊� 0 - 1000; enlarge: { type: [Number, String], default: 1 }, // 鑷姩棰勮鐨勫浐瀹氬搴� preW: { type: [Number, String], default: 0 }, /* 鍥剧墖甯冨眬鏂瑰紡 mode 瀹炵幇鍜宑ss鑳屾櫙涓€鏍风殑鏁堟灉 contain 灞呬腑甯冨眬 榛樿涓嶄細缂╂斁 淇濊瘉鍥剧墖鍦ㄥ鍣ㄩ噷闈� mode: 'contain' cover 鎷変几甯冨眬 濉厖鏁翠釜瀹瑰櫒 mode: 'cover' 濡傛灉浠呮湁涓€涓暟鍊艰缁欏畾锛岃繖涓暟鍊煎皢浣滀负瀹藉害鍊煎ぇ灏忥紝楂樺害鍊煎皢琚瀹氫负auto銆� mode: '50px' 濡傛灉鏈変袱涓暟鍊艰缁欏畾锛岀涓€涓皢浣滀负瀹藉害鍊煎ぇ灏忥紝绗簩涓綔涓洪珮搴﹀€煎ぇ灏忋€� mode: '50px 60px' */ mode: { type: String, default: "contain" }, //闄愬埗鏈€灏忓尯鍩�,鍙紶1浠ヤ笂鐨勬暟瀛楀拰瀛楃涓诧紝闄愬埗闀垮閮芥槸杩欎箞澶� // 涔熷彲浠ヤ紶鏁扮粍[90,90] limitMinSize: { type: [Number, Array, String], default: () => { return 10; }, validator: function (value) { if (Array.isArray(value)) { return Number(value[0]) >= 0 && Number(value[1]) >= 0; } else { return Number(value) >= 0; } }, }, }, computed: { cropInfo() { let obj = {}; obj.top = this.cropOffsertY > 21 ? "-21px" : "0px"; obj.width = this.cropW > 0 ? this.cropW : 0; obj.height = this.cropH > 0 ? this.cropH : 0; if (this.infoTrue) { let dpr = 1; if (this.high && !this.full) { dpr = window.devicePixelRatio; } if ((this.enlarge !== 1) & !this.full) { dpr = Math.abs(Number(this.enlarge)); } obj.width = obj.width * dpr; obj.height = obj.height * dpr; if (this.full) { obj.width = obj.width / this.scale; obj.height = obj.height / this.scale; } } obj.width = obj.width.toFixed(0); obj.height = obj.height.toFixed(0); return obj; }, isIE() { var userAgent = navigator.userAgent; //鍙栧緱娴忚鍣ㄧ殑userAgent瀛楃涓� const isIE = !!window.ActiveXObject || 'ActiveXObject' in window; //鍒ゆ柇鏄惁IE娴忚鍣� return isIE; }, passive () { return this.isIE ? null : { passive: false } } }, watch: { // 濡傛灉鍥剧墖鏀瑰彉锛� 閲嶆柊甯冨眬 img() { // 褰撲紶鍏ュ浘鐗囨椂, 璇诲彇鍥剧墖淇℃伅鍚屾椂灞曠ず this.checkedImg(); }, imgs(val) { if (val === "") { return; } this.reload(); }, cropW() { this.showPreview(); }, cropH() { this.showPreview(); }, cropOffsertX() { this.showPreview(); }, cropOffsertY() { this.showPreview(); }, scale(val, oldVal) { this.showPreview(); }, x() { this.showPreview(); }, y() { this.showPreview(); }, autoCrop(val) { if (val) { this.goAutoCrop(); } }, // 淇敼浜嗚嚜鍔ㄦ埅鍥炬 autoCropWidth() { if (this.autoCrop) { this.goAutoCrop(); } }, autoCropHeight() { if (this.autoCrop) { this.goAutoCrop(); } }, mode() { this.checkedImg(); }, rotate() { this.showPreview(); if (this.autoCrop) { this.goAutoCrop(this.cropW, this.cropH); } else { if (this.cropW > 0 || this.cropH > 0) { this.goAutoCrop(this.cropW, this.cropH); } } }, }, methods: { getVersion (name) { var arr = navigator.userAgent.split(' '); var chromeVersion = ''; let result = 0; const reg = new RegExp(name, 'i') for(var i=0;i < arr.length;i++){ if(reg.test(arr[i])) chromeVersion = arr[i] } if(chromeVersion){ result = chromeVersion.split('/')[1].split('.'); } else { result = ['0', '0', '0']; } return result }, checkOrientationImage(img, orientation, width, height) { // 濡傛灉鏄� chrome鍐呮牳鐗堟湰鍦�81 safari 鍦� 605 浠ヤ笂涓嶅鐞嗗浘鐗囨棆杞� // alert(navigator.userAgent) if (this.getVersion('chrome')[0] >= 81) { orientation = -1 } else { if (this.getVersion('safari')[0] >= 605 ) { const safariVersion = this.getVersion('version') if (safariVersion[0] > 13 && safariVersion[1] > 1) { orientation = -1 } } else { // 鍒ゆ柇 ios 鐗堟湰杩涜澶勭悊 // 閽堝 ios 鐗堟湰澶т簬 13.4鐨勭郴缁熶笉鍋氬浘鐗囨棆杞� const isIos = navigator.userAgent.toLowerCase().match(/cpu iphone os (.*?) like mac os/) if (isIos) { let version = isIos[1] version = version.split('_') if (version[0] > 13 || (version[0] >= 13 && version[1] >= 4)) { orientation = -1 } } } } // alert(`褰撳墠澶勭悊鐨刼rientation${orientation}`) let canvas = document.createElement("canvas"); let ctx = canvas.getContext("2d"); ctx.save(); switch (orientation) { case 2: canvas.width = width; canvas.height = height; // horizontal flip ctx.translate(width, 0); ctx.scale(-1, 1); break; case 3: canvas.width = width; canvas.height = height; //180 graus ctx.translate(width / 2, height / 2); ctx.rotate((180 * Math.PI) / 180); ctx.translate(-width / 2, -height / 2); break; case 4: canvas.width = width; canvas.height = height; // vertical flip ctx.translate(0, height); ctx.scale(1, -1); break; case 5: // vertical flip + 90 rotate right canvas.height = width; canvas.width = height; ctx.rotate(0.5 * Math.PI); ctx.scale(1, -1); break; case 6: canvas.width = height; canvas.height = width; //90 graus ctx.translate(height / 2, width / 2); ctx.rotate((90 * Math.PI) / 180); ctx.translate(-width / 2, -height / 2); break; case 7: // horizontal flip + 90 rotate right canvas.height = width; canvas.width = height; ctx.rotate(0.5 * Math.PI); ctx.translate(width, -height); ctx.scale(-1, 1); break; case 8: canvas.height = width; canvas.width = height; //-90 graus ctx.translate(height / 2, width / 2); ctx.rotate((-90 * Math.PI) / 180); ctx.translate(-width / 2, -height / 2); break; default: canvas.width = width; canvas.height = height; } ctx.drawImage(img, 0, 0, width, height); ctx.restore(); canvas.toBlob( blob => { let data = URL.createObjectURL(blob); URL.revokeObjectURL(this.imgs) this.imgs = data; }, "image/" + this.outputType, 1 ); }, // checkout img checkedImg() { if (this.img === null || this.img === '') { this.imgs = '' this.clearCrop() return } this.loading = true; this.scale = 1; this.rotate = 0; this.clearCrop(); let img = new Image(); img.onload = () => { if (this.img === "") { this.$emit("img-load", "error"); return false; } let width = img.width; let height = img.height; exifmin.getData(img).then(data => { this.orientation = data.orientation || 1; let max = Number(this.maxImgSize); if (!this.orientation && (width < max) & (height < max)) { this.imgs = this.img; return; } if (width > max) { height = (height / width) * max; width = max; } if (height > max) { width = (width / height) * max; height = max; } this.checkOrientationImage(img, this.orientation, width, height); }); }; img.onerror = () => { this.$emit("img-load", "error"); }; // 鍒ゆ柇濡傛灉涓嶆槸base64鍥剧墖 鍐嶆坊鍔燾rossOrigin灞炴€э紝鍚﹀垯浼氬鑷磇OS浣庣増鏈�(10.2)鏃犳硶鏄剧ず鍥剧墖 if (this.img.substr(0, 4) !== "data") { img.crossOrigin = ""; } if (this.isIE) { var xhr = new XMLHttpRequest(); xhr.onload = function() { var url = URL.createObjectURL(this.response); img.src = url; }; xhr.open("GET", this.img, true); xhr.responseType = "blob"; xhr.send(); } else { img.src = this.img; } }, // 褰撴寜涓嬮紶鏍囬敭 startMove(e) { e.preventDefault(); // 濡傛灉move 涓簍rue 琛ㄧず褰撳墠鍙互鎷栧姩 if (this.move && !this.crop) { if (!this.canMove) { return false; } // 寮€濮嬬Щ鍔� this.moveX = ('clientX' in e ? e.clientX : e.touches[0].clientX) - this.x; this.moveY = ('clientY' in e ? e.clientY : e.touches[0].clientY) - this.y; if (e.touches) { window.addEventListener("touchmove", this.moveImg); window.addEventListener("touchend", this.leaveImg); if (e.touches.length == 2) { // 璁板綍鎵嬫寚鍒氬垰鏀句笂鍘� this.touches = e.touches; window.addEventListener("touchmove", this.touchScale); window.addEventListener("touchend", this.cancelTouchScale); } } else { window.addEventListener("mousemove", this.moveImg); window.addEventListener("mouseup", this.leaveImg); } // 瑙﹀彂鍥剧墖绉诲姩浜嬩欢 this.$emit("img-moving", { moving: true, axis: this.getImgAxis() }); } else { // 鎴浘ing this.cropping = true; // 缁戝畾鎴浘浜嬩欢 window.addEventListener("mousemove", this.createCrop); window.addEventListener("mouseup", this.endCrop); window.addEventListener("touchmove", this.createCrop); window.addEventListener("touchend", this.endCrop); this.cropOffsertX = e.offsetX ? e.offsetX : e.touches[0].pageX - this.$refs.cropper.offsetLeft; this.cropOffsertY = e.offsetY ? e.offsetY : e.touches[0].pageY - this.$refs.cropper.offsetTop; this.cropX = 'clientX' in e ? e.clientX : e.touches[0].clientX; this.cropY = 'clientY' in e ? e.clientY : e.touches[0].clientY; this.cropChangeX = this.cropOffsertX; this.cropChangeY = this.cropOffsertY; this.cropW = 0; this.cropH = 0; } }, // 绉诲姩绔缉鏀� touchScale(e) { e.preventDefault(); let scale = this.scale; // 璁板綍鍙樺寲閲� // 绗竴鏍规墜鎸� var oldTouch1 = { x: this.touches[0].clientX, y: this.touches[0].clientY }; var newTouch1 = { x: e.touches[0].clientX, y: e.touches[0].clientY }; // 绗簩鏍规墜鎸� var oldTouch2 = { x: this.touches[1].clientX, y: this.touches[1].clientY }; var newTouch2 = { x: e.touches[1].clientX, y: e.touches[1].clientY }; var oldL = Math.sqrt( Math.pow(oldTouch1.x - oldTouch2.x, 2) + Math.pow(oldTouch1.y - oldTouch2.y, 2) ); var newL = Math.sqrt( Math.pow(newTouch1.x - newTouch2.x, 2) + Math.pow(newTouch1.y - newTouch2.y, 2) ); var cha = newL - oldL; // 鏍规嵁鍥剧墖鏈韩澶у皬 鍐冲畾姣忔鏀瑰彉澶у皬鐨勭郴鏁�, 鍥剧墖瓒婂ぇ绯绘暟瓒婂皬 // 1px - 0.2 var coe = 1; coe = coe / this.trueWidth > coe / this.trueHeight ? coe / this.trueHeight : coe / this.trueWidth; coe = coe > 0.1 ? 0.1 : coe; var num = coe * cha; if (!this.touchNow) { this.touchNow = true; if (cha > 0) { scale += Math.abs(num); } else if (cha < 0) { scale > Math.abs(num) ? (scale -= Math.abs(num)) : scale; } this.touches = e.touches; setTimeout(() => { this.touchNow = false; }, 8); if (!this.checkoutImgAxis(this.x, this.y, scale)) { return false; } this.scale = scale; } }, cancelTouchScale(e) { window.removeEventListener("touchmove", this.touchScale); }, // 绉诲姩鍥剧墖 moveImg(e) { e.preventDefault(); if (e.touches && e.touches.length === 2) { this.touches = e.touches; window.addEventListener("touchmove", this.touchScale); window.addEventListener("touchend", this.cancelTouchScale); window.removeEventListener("touchmove", this.moveImg); return false; } let nowX = 'clientX' in e ? e.clientX : e.touches[0].clientX; let nowY = 'clientY' in e ? e.clientY : e.touches[0].clientY; let changeX, changeY; changeX = nowX - this.moveX; changeY = nowY - this.moveY; this.$nextTick(() => { if (this.centerBox) { let axis = this.getImgAxis(changeX, changeY, this.scale); let cropAxis = this.getCropAxis(); let imgW = this.trueHeight * this.scale; let imgH = this.trueWidth * this.scale; let maxLeft, maxTop, maxRight, maxBottom; switch (this.rotate) { case 1: case -1: case 3: case -3: maxLeft = this.cropOffsertX - (this.trueWidth * (1 - this.scale)) / 2 + (imgW - imgH) / 2; maxTop = this.cropOffsertY - (this.trueHeight * (1 - this.scale)) / 2 + (imgH - imgW) / 2; maxRight = maxLeft - imgW + this.cropW; maxBottom = maxTop - imgH + this.cropH; break; default: maxLeft = this.cropOffsertX - (this.trueWidth * (1 - this.scale)) / 2; maxTop = this.cropOffsertY - (this.trueHeight * (1 - this.scale)) / 2; maxRight = maxLeft - imgH + this.cropW; maxBottom = maxTop - imgW + this.cropH; break; } // 鍥剧墖宸﹁竟 鍥剧墖涓嶈兘瓒呰繃鎴浘妗� if (axis.x1 >= cropAxis.x1) { changeX = maxLeft; } // 鍥剧墖涓婅竟 鍥剧墖涓嶈兘瓒呰繃鎴浘妗� if (axis.y1 >= cropAxis.y1) { changeY = maxTop; } // 鍥剧墖鍙宠竟 if (axis.x2 <= cropAxis.x2) { changeX = maxRight; } // 鍥剧墖涓嬭竟 if (axis.y2 <= cropAxis.y2) { changeY = maxBottom; } } this.x = changeX; this.y = changeY; // 瑙﹀彂鍥剧墖绉诲姩浜嬩欢 this.$emit("img-moving", { moving: true, axis: this.getImgAxis() }); }); }, // 绉诲姩鍥剧墖缁撴潫 leaveImg(e) { window.removeEventListener("mousemove", this.moveImg); window.removeEventListener("touchmove", this.moveImg); window.removeEventListener("mouseup", this.leaveImg); window.removeEventListener("touchend", this.leaveImg); // 瑙﹀彂鍥剧墖绉诲姩浜嬩欢 this.$emit("img-moving", { moving: false, axis: this.getImgAxis() }); }, // 缂╂斁鍥剧墖 scaleImg() { if (this.canScale) { window.addEventListener(this.support, this.changeSize, this.passive); } }, // 绉诲嚭妗� cancelScale() { if (this.canScale) { window.removeEventListener(this.support, this.changeSize); } }, // 鏀瑰彉澶у皬鍑芥暟 changeSize(e) { e.preventDefault(); let scale = this.scale; var change = e.deltaY || e.wheelDelta; // 鏍规嵁鍥剧墖鏈韩澶у皬 鍐冲畾姣忔鏀瑰彉澶у皬鐨勭郴鏁�, 鍥剧墖瓒婂ぇ绯绘暟瓒婂皬 var isFirefox = navigator.userAgent.indexOf("Firefox"); change = isFirefox > 0 ? change * 30 : change; // 淇ie鐨勬粴鍔ㄧ缉鏀� if (this.isIE) { change = -change; } // 1px - 0.2 var coe = this.coe; coe = coe / this.trueWidth > coe / this.trueHeight ? coe / this.trueHeight : coe / this.trueWidth; var num = coe * change; num < 0 ? (scale += Math.abs(num)) : scale > Math.abs(num) ? (scale -= Math.abs(num)) : scale; // 寤惰繜0.1s 姣忔鏀惧ぇ澶ф垨鑰呯缉灏忕殑鑼冨洿 let status = num < 0 ? "add" : "reduce"; if (status !== this.coeStatus) { this.coeStatus = status; this.coe = 0.2; } if (!this.scaling) { this.scalingSet = setTimeout(() => { this.scaling = false; this.coe = this.coe += 0.01; }, 50); } this.scaling = true; if (!this.checkoutImgAxis(this.x, this.y, scale)) { return false; } this.scale = scale; }, // 淇敼鍥剧墖澶у皬鍑芥暟 changeScale(num) { let scale = this.scale; num = num || 1; var coe = 20; coe = coe / this.trueWidth > coe / this.trueHeight ? coe / this.trueHeight : coe / this.trueWidth; num = num * coe; num > 0 ? (scale += Math.abs(num)) : scale > Math.abs(num) ? (scale -= Math.abs(num)) : scale; if (!this.checkoutImgAxis(this.x, this.y, scale)) { return false; } this.scale = scale; }, // 鍒涘缓鎴浘妗� createCrop(e) { e.preventDefault(); // 绉诲姩鐢熸垚澶у皬 var nowX = 'clientX' in e ? e.clientX : e.touches ? e.touches[0].clientX : 0; var nowY = 'clientY' in e ? e.clientY : e.touches ? e.touches[0].clientY : 0; this.$nextTick(() => { var fw = nowX - this.cropX; var fh = nowY - this.cropY; if (fw > 0) { this.cropW = fw + this.cropChangeX > this.w ? this.w - this.cropChangeX : fw; this.cropOffsertX = this.cropChangeX; } else { this.cropW = this.w - this.cropChangeX + Math.abs(fw) > this.w ? this.cropChangeX : Math.abs(fw); this.cropOffsertX = this.cropChangeX + fw > 0 ? this.cropChangeX + fw : 0; } if (!this.fixed) { if (fh > 0) { this.cropH = fh + this.cropChangeY > this.h ? this.h - this.cropChangeY : fh; this.cropOffsertY = this.cropChangeY; } else { this.cropH = this.h - this.cropChangeY + Math.abs(fh) > this.h ? this.cropChangeY : Math.abs(fh); this.cropOffsertY = this.cropChangeY + fh > 0 ? this.cropChangeY + fh : 0; } } else { var fixedHeight = (this.cropW / this.fixedNumber[0]) * this.fixedNumber[1]; if (fixedHeight + this.cropOffsertY > this.h) { this.cropH = this.h - this.cropOffsertY; this.cropW = (this.cropH / this.fixedNumber[1]) * this.fixedNumber[0]; if (fw > 0) { this.cropOffsertX = this.cropChangeX; } else { this.cropOffsertX = this.cropChangeX - this.cropW; } } else { this.cropH = fixedHeight; } this.cropOffsertY = this.cropOffsertY; } }); }, // 鏀瑰彉鎴浘妗嗗ぇ灏� changeCropSize(e, w, h, typeW, typeH) { e.preventDefault(); window.addEventListener("mousemove", this.changeCropNow); window.addEventListener("mouseup", this.changeCropEnd); window.addEventListener("touchmove", this.changeCropNow); window.addEventListener("touchend", this.changeCropEnd); this.canChangeX = w; this.canChangeY = h; this.changeCropTypeX = typeW; this.changeCropTypeY = typeH; this.cropX = 'clientX' in e ? e.clientX : e.touches[0].clientX; this.cropY = 'clientY' in e ? e.clientY : e.touches[0].clientY; this.cropOldW = this.cropW; this.cropOldH = this.cropH; this.cropChangeX = this.cropOffsertX; this.cropChangeY = this.cropOffsertY; if (this.fixed) { if (this.canChangeX && this.canChangeY) { this.canChangeY = 0; } } this.$emit('change-crop-size', { width: this.cropW, height: this.cropH }) }, // 姝e湪鏀瑰彉 changeCropNow(e) { e.preventDefault(); var nowX = 'clientX' in e ? e.clientX : e.touches ? e.touches[0].clientX : 0; var nowY = 'clientY' in e ? e.clientY : e.touches ? e.touches[0].clientY : 0; // 瀹瑰櫒鐨勫楂� let wrapperW = this.w; let wrapperH = this.h; // 涓嶈兘瓒呰繃鐨勫潗鏍囪酱 let minX = 0; let minY = 0; if (this.centerBox) { let axis = this.getImgAxis(); let imgW = axis.x2; let imgH = axis.y2; minX = axis.x1 > 0 ? axis.x1 : 0; minY = axis.y1 > 0 ? axis.y1 : 0; if (wrapperW > imgW) { wrapperW = imgW; } if (wrapperH > imgH) { wrapperH = imgH; } } const [minCropW, minCropH] = this.checkCropLimitSize() this.$nextTick(() => { var fw = nowX - this.cropX; var fh = nowY - this.cropY; if (this.canChangeX) { if (this.changeCropTypeX === 1) { if (this.cropOldW - fw < minCropW) { this.cropW = minCropW this.cropOffsertX = this.cropOldW + this.cropChangeX - minX - minCropW } else if (this.cropOldW - fw > 0) { this.cropW = wrapperW - this.cropChangeX - fw <= wrapperW - minX ? this.cropOldW - fw : this.cropOldW + this.cropChangeX - minX; this.cropOffsertX = wrapperW - this.cropChangeX - fw <= wrapperW - minX ? this.cropChangeX + fw : minX; } else { this.cropW = Math.abs(fw) + this.cropChangeX <= wrapperW ? Math.abs(fw) - this.cropOldW : wrapperW - this.cropOldW - this.cropChangeX; this.cropOffsertX = this.cropChangeX + this.cropOldW; } } else if (this.changeCropTypeX === 2) { if (this.cropOldW + fw < minCropW) { this.cropW = minCropW } else if (this.cropOldW + fw > 0) { this.cropW = this.cropOldW + fw + this.cropOffsertX <= wrapperW ? this.cropOldW + fw : wrapperW - this.cropOffsertX; this.cropOffsertX = this.cropChangeX; } else { // 鍙充晶鍧愭爣鎶� 瓒呰繃宸︿晶 this.cropW = wrapperW - this.cropChangeX + Math.abs(fw + this.cropOldW) <= wrapperW - minX ? Math.abs(fw + this.cropOldW) : this.cropChangeX - minX; this.cropOffsertX = wrapperW - this.cropChangeX + Math.abs(fw + this.cropOldW) <= wrapperW - minX ? this.cropChangeX - Math.abs(fw + this.cropOldW) : minX; } } } if (this.canChangeY) { if (this.changeCropTypeY === 1) { if (this.cropOldH - fh < minCropH) { this.cropH = minCropH this.cropOffsertY = this.cropOldH + this.cropChangeY - minY - minCropH } else if (this.cropOldH - fh > 0) { this.cropH = wrapperH - this.cropChangeY - fh <= wrapperH - minY ? this.cropOldH - fh : this.cropOldH + this.cropChangeY - minY; this.cropOffsertY = wrapperH - this.cropChangeY - fh <= wrapperH - minY ? this.cropChangeY + fh : minY; } else { this.cropH = Math.abs(fh) + this.cropChangeY <= wrapperH ? Math.abs(fh) - this.cropOldH : wrapperH - this.cropOldH - this.cropChangeY; this.cropOffsertY = this.cropChangeY + this.cropOldH; } } else if (this.changeCropTypeY === 2) { if (this.cropOldH + fh < minCropH) { this.cropH = minCropH } else if (this.cropOldH + fh > 0) { this.cropH = this.cropOldH + fh + this.cropOffsertY <= wrapperH ? this.cropOldH + fh : wrapperH - this.cropOffsertY; this.cropOffsertY = this.cropChangeY; } else { this.cropH = wrapperH - this.cropChangeY + Math.abs(fh + this.cropOldH) <= wrapperH - minY ? Math.abs(fh + this.cropOldH) : this.cropChangeY - minY; this.cropOffsertY = wrapperH - this.cropChangeY + Math.abs(fh + this.cropOldH) <= wrapperH - minY ? this.cropChangeY - Math.abs(fh + this.cropOldH) : minY; } } } if (this.canChangeX && this.fixed) { var fixedHeight = (this.cropW / this.fixedNumber[0]) * this.fixedNumber[1]; if (fixedHeight < minCropH) { this.cropH = minCropH this.cropW = this.fixedNumber[0] * minCropH / this.fixedNumber[1] // 杩欓噷闇€瑕佸幓淇敼 offsetX鐨勫€硷紝鍘昏皟鏁村洜涓洪珮搴﹀彉鍖栬€屽鑷寸殑瀹藉害鍙樺寲 if (this.changeCropTypeX === 1) { this.cropOffsertX = this.cropChangeX + (this.cropOldW - this.cropW) } } else if (fixedHeight + this.cropOffsertY > wrapperH) { this.cropH = wrapperH - this.cropOffsertY; this.cropW = (this.cropH / this.fixedNumber[1]) * this.fixedNumber[0]; if (this.changeCropTypeX === 1) { this.cropOffsertX = this.cropChangeX + (this.cropOldW - this.cropW) } } else { this.cropH = fixedHeight; } } if (this.canChangeY && this.fixed) { var fixedWidth = (this.cropH / this.fixedNumber[1]) * this.fixedNumber[0]; if (fixedWidth < minCropW) { this.cropW = minCropW this.cropH = this.fixedNumber[1] * minCropW / this.fixedNumber[0]; this.cropOffsertY = this.cropOldH + this.cropChangeY - this.cropH } else if (fixedWidth + this.cropOffsertX > wrapperW) { this.cropW = wrapperW - this.cropOffsertX; this.cropH = (this.cropW / this.fixedNumber[0]) * this.fixedNumber[1]; } else { this.cropW = fixedWidth; } } }); }, checkCropLimitSize () { let { cropW, cropH, limitMinSize } = this; let limitMinNum = new Array; if (!Array.isArray(limitMinSize)) { limitMinNum = [limitMinSize, limitMinSize] } else { limitMinNum = limitMinSize } //闄愬埗鏈€灏忓搴﹀拰楂樺害 cropW = parseFloat(limitMinNum[0]) cropH = parseFloat(limitMinNum[1]) return [cropW, cropH] }, // 缁撴潫鏀瑰彉 changeCropEnd(e) { window.removeEventListener("mousemove", this.changeCropNow); window.removeEventListener("mouseup", this.changeCropEnd); window.removeEventListener("touchmove", this.changeCropNow); window.removeEventListener("touchend", this.changeCropEnd); }, // 鏍规嵁姣斾緥x/y锛屾渶灏忓搴︼紝鏈€灏忛珮搴︼紝鐜版湁瀹藉害锛岀幇鏈夐珮搴︼紝寰楀埌搴旇鏈夌殑瀹藉害鍜岄珮搴� calculateSize(x, y, minX, minY, w, h) { const ratio = x / y; let width = w; let height = h; // 鍏堟牴鎹渶灏忓搴︽潵璁$畻楂樺害 if (width < minX) { width = minX; height = Math.ceil(width / ratio); } // 濡傛灉璁$畻鍑烘潵鐨勯珮搴﹀皬浜庢渶灏忛珮搴︼紝鍒欐牴鎹渶灏忛珮搴︽潵閲嶆柊璁$畻瀹藉害鍜岄珮搴� if (height < minY) { height = minY; width = Math.ceil(height * ratio); // 濡傛灉閲嶆柊璁$畻鐨勫搴︿粛鐒跺皬浜庢渶灏忓搴︼紝鍒欎娇鐢ㄦ渶灏忓搴︼紝骞堕噸鏂拌绠楅珮搴� if (width < minX) { width = minX; height = Math.ceil(width / ratio); } } // 濡傛灉璁$畻鍑烘潵鐨勫搴︽垨楂樺害灏忎簬杈撳叆鐨勫搴︽垨楂樺害锛屽垯鍒嗗埆浣跨敤杈撳叆鐨勫搴︽垨楂樺害 if (width < w) { width = w; height = Math.ceil(width / ratio); } if (height < h) { height = h; width = Math.ceil(height * ratio); } return { width, height }; }, // 鍒涘缓瀹屾垚 endCrop() { if (this.cropW === 0 && this.cropH === 0) { this.cropping = false; } let [minCropW, minCropH] = this.checkCropLimitSize(); const { width, height } = this.fixed ? this.calculateSize( this.fixedNumber[0], this.fixedNumber[1], minCropW, minCropH, this.cropW, this.cropH ) : { width: minCropW, height: minCropH } if (width > this.cropW) { this.cropW = width; if (this.cropOffsertX + width > this.w) { this.cropOffsertX = this.w - width; } } if (height > this.cropH) { this.cropH = height; if (this.cropOffsertY + height > this.h) { this.cropOffsertY = this.h - height; } } window.removeEventListener("mousemove", this.createCrop); window.removeEventListener("mouseup", this.endCrop); window.removeEventListener("touchmove", this.createCrop); window.removeEventListener("touchend", this.endCrop); }, // 寮€濮嬫埅鍥� startCrop() { this.crop = true; }, // 鍋滄鎴浘 stopCrop() { this.crop = false; }, // 娓呴櫎鎴浘 clearCrop() { this.cropping = false; this.cropW = 0; this.cropH = 0; }, // 鎴浘绉诲姩 cropMove(e) { e.preventDefault(); if (!this.canMoveBox) { this.crop = false; this.startMove(e); return false; } if (e.touches && e.touches.length === 2) { this.crop = false; this.startMove(e); this.leaveCrop(); return false; } window.addEventListener("mousemove", this.moveCrop); window.addEventListener("mouseup", this.leaveCrop); window.addEventListener("touchmove", this.moveCrop); window.addEventListener("touchend", this.leaveCrop); let x = 'clientX' in e ? e.clientX : e.touches[0].clientX; let y = 'clientY' in e ? e.clientY : e.touches[0].clientY; let newX, newY; newX = x - this.cropOffsertX; newY = y - this.cropOffsertY; this.cropX = newX; this.cropY = newY; // 瑙﹀彂鎴浘妗嗙Щ鍔ㄤ簨浠� this.$emit("crop-moving", { moving: true, axis: this.getCropAxis() }); }, moveCrop(e, isMove) { let nowX = 0; let nowY = 0; if (e) { e.preventDefault(); nowX = 'clientX' in e ? e.clientX : e.touches[0].clientX; nowY = 'clientY' in e ? e.clientY : e.touches[0].clientY; } this.$nextTick(() => { let cx, cy; let fw = nowX - this.cropX; let fh = nowY - this.cropY; if (isMove) { fw = this.cropOffsertX; fh = this.cropOffsertY; } // 涓嶈兘瓒呰繃澶栧眰瀹瑰櫒 if (fw <= 0) { cx = 0; } else if (fw + this.cropW > this.w) { cx = this.w - this.cropW; } else { cx = fw; } if (fh <= 0) { cy = 0; } else if (fh + this.cropH > this.h) { cy = this.h - this.cropH; } else { cy = fh; } // 涓嶈兘瓒呰繃鍥剧墖 if (this.centerBox) { let axis = this.getImgAxis(); // 妯潗鏍囧垽鏂� if (cx <= axis.x1) { cx = axis.x1; } if (cx + this.cropW > axis.x2) { cx = axis.x2 - this.cropW; } // 绾靛潗鏍囩旱杞� if (cy <= axis.y1) { cy = axis.y1; } if (cy + this.cropH > axis.y2) { cy = axis.y2 - this.cropH; } } this.cropOffsertX = cx; this.cropOffsertY = cy; // 瑙﹀彂鎴浘妗嗙Щ鍔ㄤ簨浠� this.$emit("crop-moving", { moving: true, axis: this.getCropAxis() }); }); }, // 绠楀嚭涓嶅悓鍦烘櫙涓嬮潰 鍥剧墖鐩稿浜庡灞傚鍣ㄧ殑鍧愭爣杞� getImgAxis(x, y, scale) { x = x || this.x; y = y || this.y; scale = scale || this.scale; // 濡傛灉璁剧疆浜嗘埅鍥炬鍦ㄥ浘鐗囧唴锛� 閭d箞闄愬埗鎴浘妗嗕笉鑳借秴杩囧浘鐗囩殑鍧愭爣 // 鍥剧墖鐨勫潗鏍� let obj = { x1: 0, x2: 0, y1: 0, y2: 0 }; let imgW = this.trueWidth * scale; let imgH = this.trueHeight * scale; switch (this.rotate) { case 0: obj.x1 = x + (this.trueWidth * (1 - scale)) / 2; obj.x2 = obj.x1 + this.trueWidth * scale; obj.y1 = y + (this.trueHeight * (1 - scale)) / 2; obj.y2 = obj.y1 + this.trueHeight * scale; break; case 1: case -1: case 3: case -3: obj.x1 = x + (this.trueWidth * (1 - scale)) / 2 + (imgW - imgH) / 2; obj.x2 = obj.x1 + this.trueHeight * scale; obj.y1 = y + (this.trueHeight * (1 - scale)) / 2 + (imgH - imgW) / 2; obj.y2 = obj.y1 + this.trueWidth * scale; break; default: obj.x1 = x + (this.trueWidth * (1 - scale)) / 2; obj.x2 = obj.x1 + this.trueWidth * scale; obj.y1 = y + (this.trueHeight * (1 - scale)) / 2; obj.y2 = obj.y1 + this.trueHeight * scale; break; } return obj; }, // 鑾峰彇鎴浘妗嗙殑鍧愭爣杞� getCropAxis() { let obj = { x1: 0, x2: 0, y1: 0, y2: 0 }; obj.x1 = this.cropOffsertX; obj.x2 = obj.x1 + this.cropW; obj.y1 = this.cropOffsertY; obj.y2 = obj.y1 + this.cropH; return obj; }, leaveCrop(e) { window.removeEventListener("mousemove", this.moveCrop); window.removeEventListener("mouseup", this.leaveCrop); window.removeEventListener("touchmove", this.moveCrop); window.removeEventListener("touchend", this.leaveCrop); // 瑙﹀彂鎴浘妗嗙Щ鍔ㄤ簨浠� this.$emit("crop-moving", { moving: false, axis: this.getCropAxis() }); }, getCropChecked(cb) { let canvas = document.createElement("canvas"); let img = new Image(); let rotate = this.rotate; let trueWidth = this.trueWidth; let trueHeight = this.trueHeight; let cropOffsertX = this.cropOffsertX; let cropOffsertY = this.cropOffsertY; img.onload = () => { if (this.cropW !== 0) { let ctx = canvas.getContext("2d"); let dpr = 1; if (this.high & !this.full) { dpr = window.devicePixelRatio; } if ((this.enlarge !== 1) & !this.full) { dpr = Math.abs(Number(this.enlarge)); } let width = this.cropW * dpr; let height = this.cropH * dpr; let imgW = trueWidth * this.scale * dpr; let imgH = trueHeight * this.scale * dpr; // 鍥剧墖x杞村亸绉� let dx = (this.x - cropOffsertX + (this.trueWidth * (1 - this.scale)) / 2) * dpr; // 鍥剧墖y杞村亸绉� let dy = (this.y - cropOffsertY + (this.trueHeight * (1 - this.scale)) / 2) * dpr; //淇濆瓨鐘舵€� setCanvasSize(width, height); ctx.save(); switch (rotate) { case 0: if (!this.full) { ctx.drawImage(img, dx, dy, imgW, imgH); } else { // 杈撳嚭鍘熷浘姣斾緥鎴浘 setCanvasSize(width / this.scale, height / this.scale); ctx.drawImage( img, dx / this.scale, dy / this.scale, imgW / this.scale, imgH / this.scale ); } break; case 1: case -3: if (!this.full) { // 鎹㈢畻鍥剧墖鏃嬭浆鍚庣殑鍧愭爣寮ヨˉ dx = dx + (imgW - imgH) / 2; dy = dy + (imgH - imgW) / 2; ctx.rotate((rotate * 90 * Math.PI) / 180); ctx.drawImage(img, dy, -dx - imgH, imgW, imgH); } else { setCanvasSize(width / this.scale, height / this.scale); // 鎹㈢畻鍥剧墖鏃嬭浆鍚庣殑鍧愭爣寮ヨˉ dx = dx / this.scale + (imgW / this.scale - imgH / this.scale) / 2; dy = dy / this.scale + (imgH / this.scale - imgW / this.scale) / 2; ctx.rotate((rotate * 90 * Math.PI) / 180); ctx.drawImage( img, dy, -dx - imgH / this.scale, imgW / this.scale, imgH / this.scale ); } break; case 2: case -2: if (!this.full) { ctx.rotate((rotate * 90 * Math.PI) / 180); ctx.drawImage(img, -dx - imgW, -dy - imgH, imgW, imgH); } else { setCanvasSize(width / this.scale, height / this.scale); ctx.rotate((rotate * 90 * Math.PI) / 180); dx = dx / this.scale; dy = dy / this.scale; ctx.drawImage( img, -dx - imgW / this.scale, -dy - imgH / this.scale, imgW / this.scale, imgH / this.scale ); } break; case 3: case -1: if (!this.full) { // 鎹㈢畻鍥剧墖鏃嬭浆鍚庣殑鍧愭爣寮ヨˉ dx = dx + (imgW - imgH) / 2; dy = dy + (imgH - imgW) / 2; ctx.rotate((rotate * 90 * Math.PI) / 180); ctx.drawImage(img, -dy - imgW, dx, imgW, imgH); } else { setCanvasSize(width / this.scale, height / this.scale); // 鎹㈢畻鍥剧墖鏃嬭浆鍚庣殑鍧愭爣寮ヨˉ dx = dx / this.scale + (imgW / this.scale - imgH / this.scale) / 2; dy = dy / this.scale + (imgH / this.scale - imgW / this.scale) / 2; ctx.rotate((rotate * 90 * Math.PI) / 180); ctx.drawImage( img, -dy - imgW / this.scale, dx, imgW / this.scale, imgH / this.scale ); } break; default: if (!this.full) { ctx.drawImage(img, dx, dy, imgW, imgH); } else { // 杈撳嚭鍘熷浘姣斾緥鎴浘 setCanvasSize(width / this.scale, height / this.scale); ctx.drawImage( img, dx / this.scale, dy / this.scale, imgW / this.scale, imgH / this.scale ); } } ctx.restore(); } else { let width = trueWidth * this.scale; let height = trueHeight * this.scale; let ctx = canvas.getContext("2d"); ctx.save(); switch (rotate) { case 0: setCanvasSize(width, height); ctx.drawImage(img, 0, 0, width, height); break; case 1: case -3: // 鏃嬭浆90搴� 鎴栬€�-270搴� 瀹藉害鍜岄珮搴﹀璋� setCanvasSize(height, width); ctx.rotate((rotate * 90 * Math.PI) / 180); ctx.drawImage(img, 0, -height, width, height); break; case 2: case -2: setCanvasSize(width, height); ctx.rotate((rotate * 90 * Math.PI) / 180); ctx.drawImage(img, -width, -height, width, height); break; case 3: case -1: setCanvasSize(height, width); ctx.rotate((rotate * 90 * Math.PI) / 180); ctx.drawImage(img, -width, 0, width, height); break; default: setCanvasSize(width, height); ctx.drawImage(img, 0, 0, width, height); } ctx.restore(); } cb(canvas); }; // 鍒ゆ柇鍥剧墖鏄惁鏄痓ase64 var s = this.img.substr(0, 4); if (s !== "data") { img.crossOrigin = "Anonymous"; } img.src = this.imgs; function setCanvasSize(width, height) { canvas.width = Math.round(width); canvas.height = Math.round(height); } }, // 鑾峰彇杞崲鎴恇ase64 鐨勫浘鐗囦俊鎭� getCropData(cb) { this.getCropChecked(data => { cb(data.toDataURL("image/" + this.outputType, this.outputSize)); }); }, //canvas鑾峰彇涓篵lob瀵硅薄 getCropBlob(cb) { this.getCropChecked(data => { data.toBlob( blob => cb(blob), "image/" + this.outputType, this.outputSize ); }); }, // 鑷姩棰勮鍑芥暟 showPreview() { // 浼樺寲涓嶈澶氭瑙﹀彂 if (this.isCanShow) { this.isCanShow = false; setTimeout(() => { this.isCanShow = true; }, 16); } else { return false; } let w = this.cropW; let h = this.cropH; let scale = this.scale; var obj = {}; obj.div = { width: `${w}px`, height: `${h}px` }; let transformX = (this.x - this.cropOffsertX) / scale; let transformY = (this.y - this.cropOffsertY) / scale; let transformZ = 0; obj.w = w; obj.h = h; obj.url = this.imgs; obj.img = { width: `${this.trueWidth}px`, height: `${this.trueHeight}px`, transform: `scale(${scale})translate3d(${transformX}px, ${transformY}px, ${transformZ}px)rotateZ(${this .rotate * 90}deg)` }; obj.html = ` <div class="show-preview" style="width: ${obj.w}px; height: ${ obj.h }px,; overflow: hidden"> <div style="width: ${w}px; height: ${h}px"> <img src=${obj.url} style="width: ${this.trueWidth}px; height: ${ this.trueHeight }px; transform: scale(${scale})translate3d(${transformX}px, ${transformY}px, ${transformZ}px)rotateZ(${this .rotate * 90}deg)"> </div> </div>`; this.$emit("real-time", obj); }, // reload 鍥剧墖甯冨眬鍑芥暟 reload() { let img = new Image(); img.onload = () => { // 璇诲彇鍥剧墖鐨勪俊鎭師濮嬩俊鎭紝 瑙f瀽鏄惁闇€瑕佹棆杞� // 璇诲彇鍥剧墖鐨勬棆杞俊鎭� // 寰楀埌澶栧眰瀹瑰櫒鐨勫搴﹂珮搴� this.w = parseFloat(window.getComputedStyle(this.$refs.cropper).width); this.h = parseFloat(window.getComputedStyle(this.$refs.cropper).height); // 瀛樺叆鍥剧墖鐪熷疄楂樺害 this.trueWidth = img.width; this.trueHeight = img.height; // 鍒ゆ柇鏄惁闇€瑕佸帇缂╁ぇ鍥� if (!this.original) { // 鍒ゆ柇甯冨眬鏂瑰紡 mode this.scale = this.checkedMode(); } else { this.scale = 1; } this.$nextTick(() => { this.x = -(this.trueWidth - this.trueWidth * this.scale) / 2 + (this.w - this.trueWidth * this.scale) / 2; this.y = -(this.trueHeight - this.trueHeight * this.scale) / 2 + (this.h - this.trueHeight * this.scale) / 2; this.loading = false; // // 鑾峰彇鏄惁寮€鍚簡鑷姩鎴浘 if (this.autoCrop) { this.goAutoCrop(); } // 鍥剧墖鍔犺浇鎴愬姛鐨勫洖璋� this.$emit("img-load", "success"); setTimeout(() => { this.showPreview(); }, 20); }); }; img.onerror = () => { this.$emit("img-load", "error"); }; img.src = this.imgs; }, // 鑳屾櫙甯冨眬鐨勫嚱鏁� checkedMode() { let scale = 1; // 閫氳繃瀛楃涓插垎鍓� let imgW = this.trueWidth; let imgH = this.trueHeight; const arr = this.mode.split(" "); switch (arr[0]) { case "contain": if (this.trueWidth > this.w) { // 濡傛灉鍥剧墖瀹藉害澶т簬瀹瑰櫒瀹藉害 scale = this.w / this.trueWidth; } if (this.trueHeight * scale > this.h) { scale = this.h / this.trueHeight; } break; case "cover": // 鎵╁睍甯冨眬 榛樿濉厖婊℃暣涓鍣� // 鍥剧墖瀹藉害澶т簬瀹瑰櫒 imgW = this.w; scale = imgW / this.trueWidth; imgH = imgH * scale; // 濡傛灉鎵╁睍涔嬪悗楂樺害灏忎簬瀹瑰櫒鐨勫灞傞珮搴� 缁х画鎵╁睍楂樺害 if (imgH < this.h) { imgH = this.h; scale = imgH / this.trueHeight; } break; default: try { let str = arr[0]; if (str.search("px") !== -1) { str = str.replace("px", ""); imgW = parseFloat(str); const scaleX = imgW / this.trueWidth; let scaleY = 1; let strH = arr[1]; if (strH.search("px") !== -1) { strH = strH.replace("px", ""); imgH = parseFloat(strH); scaleY = imgH / this.trueHeight; } scale = Math.min(scaleX,scaleY) } if (str.search("%") !== -1) { str = str.replace("%", ""); imgW = (parseFloat(str) / 100) * this.w; scale = imgW / this.trueWidth; } if (arr.length === 2 && str === "auto") { let str2 = arr[1]; if (str2.search("px") !== -1) { str2 = str2.replace("px", ""); imgH = parseFloat(str2); scale = imgH / this.trueHeight; } if (str2.search("%") !== -1) { str2 = str2.replace("%", ""); imgH = (parseFloat(str2) / 100) * this.h; scale = imgH / this.trueHeight; } } } catch (error) { scale = 1; } } return scale; }, // 鑷姩鎴浘鍑芥暟 goAutoCrop(cw, ch) { if (this.imgs === '' || this.imgs === null) return this.clearCrop(); this.cropping = true; let maxWidth = this.w; let maxHeight = this.h; if (this.centerBox) { const switchWH = Math.abs(this.rotate) % 2 > 0 let imgW = (switchWH ? this.trueHeight : this.trueWidth) * this.scale; let imgH = (switchWH ? this.trueWidth : this.trueHeight) * this.scale; maxWidth = imgW < maxWidth ? imgW : maxWidth; maxHeight = imgH < maxHeight ? imgH : maxHeight; } // 鎴浘妗嗛粯璁ゅぇ灏� // 濡傛灉涓�0 閭d箞璁$畻瀹瑰櫒澶у皬 榛樿涓�80% var w = cw ? cw : parseFloat(this.autoCropWidth); var h = ch ? ch : parseFloat(this.autoCropHeight); if (w === 0 || h === 0) { w = maxWidth * 0.8; h = maxHeight * 0.8; } w = w > maxWidth ? maxWidth : w; h = h > maxHeight ? maxHeight : h; if (this.fixed) { h = (w / this.fixedNumber[0]) * this.fixedNumber[1]; } // 濡傛灉姣斾緥涔嬪悗 楂樺害澶т簬h if (h > this.h) { h = this.h; w = (h / this.fixedNumber[1]) * this.fixedNumber[0]; } this.changeCrop(w, h); }, // 鎵嬪姩鏀瑰彉鎴浘妗嗗ぇ灏忓嚱鏁� changeCrop(w, h) { if (this.centerBox) { // 淇鍒濆鍖栨椂鍊欏湪centerBox=true鎯呭喌涓� let axis = this.getImgAxis(); if (w > axis.x2 - axis.x1) { // 瀹藉害瓒呮爣 w = axis.x2 - axis.x1; h = (w / this.fixedNumber[0]) * this.fixedNumber[1]; } if (h > axis.y2 - axis.y1) { // 楂樺害瓒呮爣 h = axis.y2 - axis.y1; w = (h / this.fixedNumber[1]) * this.fixedNumber[0]; } } // 鍒ゆ柇鏄惁澶т簬瀹瑰櫒 this.cropW = w; this.cropH = h; this.checkCropLimitSize() this.$nextTick(() => { // 灞呬腑璧颁竴璧� this.cropOffsertX = (this.w - this.cropW) / 2; this.cropOffsertY = (this.h - this.cropH) / 2; if (this.centerBox) { this.moveCrop(null, true); } }); }, // 閲嶇疆鍑芥暟锛� 鎭㈠缁勪欢缃垵濮嬬姸鎬� refresh() { let img = this.img; this.imgs = ""; this.scale = 1; this.crop = false; this.rotate = 0; this.w = 0; this.h = 0; this.trueWidth = 0; this.trueHeight = 0; this.clearCrop(); this.$nextTick(() => { this.checkedImg(); }); }, // 鍚戝乏杈规棆杞� rotateLeft() { this.rotate = this.rotate <= -3 ? 0 : this.rotate - 1; }, // 鍚戝彸杈规棆杞� rotateRight() { this.rotate = this.rotate >= 3 ? 0 : this.rotate + 1; }, // 娓呴櫎鏃嬭浆 rotateClear() { this.rotate = 0; }, // 鍥剧墖鍧愭爣鐐规牎楠� checkoutImgAxis(x, y, scale) { x = x || this.x; y = y || this.y; scale = scale || this.scale; let canGo = true; // 寮€濮嬫牎楠� 濡傛灉璇寸缉鏀句箣鍚庣殑鍧愭爣鍦ㄦ埅鍥炬澶� 鍒欓樆姝㈢缉鏀� if (this.centerBox) { let axis = this.getImgAxis(x, y, scale); let cropAxis = this.getCropAxis(); // 宸﹁竟鐨勬í鍧愭爣 鍥剧墖涓嶈兘瓒呰繃鎴浘妗� if (axis.x1 >= cropAxis.x1) { canGo = false; } // 鍙宠竟妯潗鏍� if (axis.x2 <= cropAxis.x2) { canGo = false; } // 绾靛潗鏍囦笂闈� if (axis.y1 >= cropAxis.y1) { canGo = false; } // 绾靛潗鏍囦笅闈� if (axis.y2 <= cropAxis.y2) { canGo = false; } } return canGo; } }, mounted() { this.support = "onwheel" in document.createElement("div") ? "wheel" : document.onmousewheel !== undefined ? "mousewheel" : "DOMMouseScroll"; let that = this; var u = navigator.userAgent; this.isIOS = !!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/); // 鍏煎blob if (!HTMLCanvasElement.prototype.toBlob) { Object.defineProperty(HTMLCanvasElement.prototype, "toBlob", { value: function(callback, type, quality) { var binStr = atob(this.toDataURL(type, quality).split(",")[1]), len = binStr.length, arr = new Uint8Array(len); for (var i = 0; i < len; i++) { arr[i] = binStr.charCodeAt(i); } callback(new Blob([arr], { type: that.type || "image/png" })); } }); } this.showPreview(); this.checkedImg(); }, unmounted() { window.removeEventListener("mousemove", this.moveCrop); window.removeEventListener("mouseup", this.leaveCrop); window.removeEventListener("touchmove", this.moveCrop); window.removeEventListener("touchend", this.leaveCrop); this.cancelScale() } }); </script> <style scoped lang="css"> .vue-cropper { position: relative; width: 100%; height: 100%; box-sizing: border-box; user-select: none; -webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; direction: ltr; touch-action: none; text-align: left; background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAAA3NCSVQICAjb4U/gAAAABlBMVEXMzMz////TjRV2AAAACXBIWXMAAArrAAAK6wGCiw1aAAAAHHRFWHRTb2Z0d2FyZQBBZG9iZSBGaXJld29ya3MgQ1M26LyyjAAAABFJREFUCJlj+M/AgBVhF/0PAH6/D/HkDxOGAAAAAElFTkSuQmCC"); } .cropper-box, .cropper-box-canvas, .cropper-drag-box, .cropper-crop-box, .cropper-face { position: absolute; top: 0; right: 0; bottom: 0; left: 0; user-select: none; } .cropper-box-canvas img { position: relative; text-align: left; user-select: none; transform: none; max-width: none; max-height: none; } .cropper-box { overflow: hidden; } .cropper-move { cursor: move; } .cropper-crop { cursor: crosshair; } .cropper-modal { background: rgba(0, 0, 0, 0.5); } .cropper-crop-box { /*border: 2px solid #39f;*/ } .cropper-view-box { display: block; overflow: hidden; width: 100%; height: 100%; outline: 1px solid #39f; outline-color: rgba(51, 153, 255, 0.75); user-select: none; } .cropper-view-box img { user-select: none; text-align: left; max-width: none; max-height: none; } .cropper-face { top: 0; left: 0; background-color: #fff; opacity: 0.1; } .crop-info { position: absolute; left: 0px; min-width: 65px; text-align: center; color: white; line-height: 20px; background-color: rgba(0, 0, 0, 0.8); font-size: 12px; } .crop-line { position: absolute; display: block; width: 100%; height: 100%; opacity: 0.1; } .line-w { top: -3px; left: 0; height: 5px; cursor: n-resize; } .line-a { top: 0; left: -3px; width: 5px; cursor: w-resize; } .line-s { bottom: -3px; left: 0; height: 5px; cursor: s-resize; } .line-d { top: 0; right: -3px; width: 5px; cursor: e-resize; } .crop-point { position: absolute; width: 8px; height: 8px; opacity: 0.75; background-color: #39f; border-radius: 100%; } .point1 { top: -4px; left: -4px; cursor: nw-resize; } .point2 { top: -5px; left: 50%; margin-left: -3px; cursor: n-resize; } .point3 { top: -4px; right: -4px; cursor: ne-resize; } .point4 { top: 50%; left: -4px; margin-top: -3px; cursor: w-resize; } .point5 { top: 50%; right: -4px; margin-top: -3px; cursor: e-resize; } .point6 { bottom: -5px; left: -4px; cursor: sw-resize; } .point7 { bottom: -5px; left: 50%; margin-left: -3px; cursor: s-resize; } .point8 { bottom: -5px; right: -4px; cursor: se-resize; } @media screen and (max-width: 500px) { .crop-point { position: absolute; width: 20px; height: 20px; opacity: 0.45; background-color: #39f; border-radius: 100%; } .point1 { top: -10px; left: -10px; } .point2, .point4, .point5, .point7 { display: none; } .point3 { top: -10px; right: -10px; } .point4 { top: 0; left: 0; } .point6 { bottom: -10px; left: -10px; } .point8 { bottom: -10px; right: -10px; } } </style>