公共裁剪页面
<style> .el-dialog__header { padding: 24px 0 11px 28px; } .el-dialog__title { color: #333333; } .el-dialog__body { padding: 0 28px; } .el-dialog__footer { padding: 20px 28px; } .avatar { display: flex; } .avatar-left { display: flex; justify-content: center; align-items: center; width: 400px; height: 400px; background-color: #F0F2F5; margin-right: 10px; border-radius: 4px; } .avatar-left-crop { width: 400px; height: 400px; position: relative; } .crop-box { width: 100%; height: 100%; border-radius: 4px; overflow: hidden } .avatar-left-p { text-align: center; width: 100%; position: absolute; bottom: 20px; color: #ffffff; font-size: 14px; } .avatar-right { width: 150px; height: 400px; background-color: #F0F2F5; border-radius: 4px; padding: 16px 0; box-sizing: border-box; } .avatar-right-div { border: 3px solid #ffffff; border-radius: 50%; } .avatar-right-previews { width: 200px; height: 200px; overflow: hidden; border-radius: 50%; } .avatar-right-text { text-align: center; margin-top: 50px; font-size: 14px; } span { color: #666666; } .cropper-view-box, .cropper-face, .preview { border-radius: 50%; } </style> <script src="~/Scripts/jquery-3.4.1.min.js"></script> <script src="~/Scripts/vue.min.js"></script> <script src="~/Scripts/ElementUI/index.js"></script> <script src="~/Scripts/ElementUI/locale/en.js"></script> <script src="~/Scripts/cropper/cropper.min.js"></script> <link href="~/Scripts/cropper/cropper.min.css" rel="stylesheet" /> <div id="app"> <div style="display: flex" class="avatar"> <div class="avatar-left"> <div v-if="!optionsPhoto.img"> @*<el-upload ref="upload" action="" style="text-align: center;margin-bottom: 24px" :on-change="uploads" accept="image/png, image/jpeg, image/jpg" :show-file-list="false" :auto-upload="false"> <el-button slot="trigger" size="small" type="primary" ref="uploadBtn">选择图片</el-button> </el-upload>*@ <input type="file" id="doc" accept="image/*" v-on:change="CropperSetImagePreview1()" /> <div>支持jpg、png格式的图片,大小不超过3M</div> </div> <div v-show="optionsPhoto.img" class="avatar-left-crop"> <div class="col col-6" id="localImag"> <img id="image" src="../docs/images/picture.jpg" alt="Picture"> </div> <p class="avatar-left-p"> 鼠标滚轮缩放控制图片显示大小,鼠标拖拽调整显示位置 </p> </div> </div> <div class="avatar-right"> <div class="avatar-right-div" v-for="item in previewsDiv" :style="item.style"> <div v-show="optionsPhoto.img" :class="previews.div" class="avatar-right-previews" :style="item.zoomStyle"> <div class="preview"></div> </div> </div> <div class="avatar-right-text"> <el-button v-if="optionsPhoto.img" type="text" v-on:click="uploadPreviews">重新上传</el-button> <span v-else>预览</span> </div> </div> </div> <span slot="footer" class="dialog-footer"> <el-button v-on:click="CropDialogVisible=false">取 消</el-button> <el-button type="primary" v-on:click="getCrop">确 定</el-button> </span> </div> <script> function each(arr, callback) { var length = arr.length; var i; for (i = 0; i < length; i++) { callback.call(arr, arr[i], i, arr); } return arr; } var cropper; $(function () { var layerIndex; ELEMENT.locale(ELEMENT.lang.en); var vue = new Vue({ el: '#app', data: { optionsPhoto: { img: false }, CropDialogVisible: false, //实时预览图数据 previews: {}, previewsDiv: [ //108px 预览样式 { style: { width: '108px', height: '108px', margin: '0 auto' }, zoomStyle: { zoom: 0.54 } }, //68px 预览样式 { style: { width: '68px', height: '68px', margin: '27px auto' }, zoomStyle: { zoom: 0.34 } }, //48px 预览样式 { style: { width: '48px', height: '48px', margin: '0 auto' }, zoomStyle: { zoom: 0.24 } } ] }, methods: { uploadPreviews: function () { }, uploads(file) { const isIMAGE = file.raw.type === 'image/jpeg' || file.raw.type === 'image/png'; const isLt3M = file.raw.size / 1024 / 1024 < 3; if (!isIMAGE) { this.$message({ showClose: true, message: '请选择 jpg、png 格式的图片!', type: 'error', //提示类型 }); return false; } if (!isLt3M) { this.$message({ showClose: true, message: '上传图片大小不能超过 3MB', type: 'error', //提示类型 }); return false; } let reader = new FileReader(); reader.readAsDataURL(file.raw); reader.onload = e => { this.optionsPhoto.img = e.target.result //base64 } }, CropperSetImagePreview: function () { this.CropDialogVisible = true; }, CropperSetImagePreview1: function () { var docObj = document.getElementById("doc"); console.log(docObj.files) var imgObjPreview = document.getElementById("image"); if (docObj.files && docObj.files[0]) { //火狐下,直接设img属性 imgObjPreview.style.display = 'block'; imgObjPreview.style.maxWidth = '960px'; imgObjPreview.style.height = '400px'; //imgObjPreview.src = docObj.files[0].getAsDataURL(); // 取绝对路径的getAsDataURL //火狐7以上版本不能用上面的getAsDataURL()方式获取,需要一下方式 imgObjPreview.src = window.URL.createObjectURL(docObj.files[0]); } else { //IE下,使用滤镜 docObj.select(); var imgSrc = document.selection.createRange().text; var localImagId = document.getElementById("localImag"); //必须设置初始大小 localImagId.style.maxWidth = "960px"; localImagId.style.height = 'auto'; //图片异常的捕捉,防止用户修改后缀来伪造图片 try { localImagId.style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(sizingMethod=scale)"; localImagId.filters.item("DXImageTransform.Microsoft.AlphaImageLoader").src = imgSrc; } catch (e) { alert("您上传的图片格式不正确,请重新选择!"); return false; } imgObjPreview.style.display = 'none'; document.selection.empty(); } this.changeFile(); this.previews.url = window.URL.createObjectURL(docObj.files[0]); this.optionsPhoto.img = true; }, changeFile: function () { var image = document.querySelector('#image'); var previews = document.querySelectorAll('.preview'); cropper = new Cropper(image, { aspectRatio: 1, toggleDragModeOnDblclick: false, cropBoxResizable: true, cropBoxMovable: true, highlight: false, center: false, guides: false, restore: false, autoCropArea: 0.65, dragMode: 'move', // movable:false, ready: function () { var clone = this.cloneNode(); croppable = true; clone.className = '' clone.style.cssText = ( 'display: block;' + 'width: 100%;' + 'min-width: 0;' + 'min-height: 0;' + 'max-width: none;' + 'max-height: none;' ); each(previews, function (elem) { elem.appendChild(clone.cloneNode()); }); }, // 类型: Function // 默认: null“ cropper” 事件的捷径。 crop: function (e) { var data = e.detail; var cropper = this.cropper; var imageData = cropper.getImageData(); //输出图像位置,大小等相关数据。 var previewAspectRatio = data.width / data.height; each(previews, function (elem) { var previewImage = elem.getElementsByTagName('img').item(0); var previewWidth = elem.offsetWidth; var previewHeight = previewWidth / previewAspectRatio; var imageScaledRatio = data.width / previewWidth; elem.style.height = previewHeight + 'px'; previewImage.style.width = imageData.naturalWidth / imageScaledRatio + 'px'; previewImage.style.height = imageData.naturalHeight / imageScaledRatio + 'px'; previewImage.style.marginLeft = -data.x / imageScaledRatio + 'px'; previewImage.style.marginTop = -data.y / imageScaledRatio + 'px'; }); }, }); }, getRoundedCanvas: function (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; }, getCrop: function () { var croppedCanvas; var roundedCanvas; var roundedImage; if (!croppable) { return; } // Crop croppedCanvas = cropper.getCroppedCanvas(); // Round roundedCanvas = this.getRoundedCanvas(croppedCanvas); // Show roundedImage = document.createElement('img'); roundedImage.src = roundedCanvas.toDataURL() blob = this.dataURLtoBlob(roundedCanvas.toDataURL()); // this.UserInfo.UserPhoto = roundedImage.src; parent.vue.CloseCropPicture(roundedImage.src); }, dataURLtoBlob: function (dataurl) { var arr = dataurl.split(','), mime = arr[0].match(/:(.*?);/)[1], bstr = atob(arr[1]), n = bstr.length, u8arr = new Uint8Array(n); while (n--) { u8arr[n] = bstr.charCodeAt(n); } return new Blob([u8arr], { type: mime }); }, }, mounted: function () { } }); }); </script>
父页面
<div class="PP--main-left"> <template v-if="IsPreview"> <img id="image" style="height:214px;width:214px" :src="UserInfo.UserPhoto" :key="UserInfo.UserPhoto" alt="Picture" /> </template> <template v-else> <div class="poto" style="cursor:pointer" v-on:click="CropperSetImagePreview()"> <template v-if="UserInfo.UserPhoto==null||UserInfo.UserPhoto==''"> <i class="pwc-icon pwc-upload-outline"></i> <span>Upload image</span> </template> <template v-else> <img style="width:214px;height:214px;" :src="UserInfo.UserPhoto" :key="UserInfo.UserPhoto"></img> </template> </div> </template> <div style="display:none"> <input type="file" id="file" accept="image/*" v-on:change="UpLoadFile(1)" /> </div> </div>
<div> <el-dialog :visible.sync="dialogVisibleCop" width="30%"> <iframe :src="frameUrlCrop" frameborder="0" width="100%" height="527px"></iframe> <span slot="footer" class="dialog-footer"> </span> </el-dialog> </div> CropperSetImagePreview: function () { this.dialogVisibleCop = true; this.frameUrlCrop=rootUrl + "Common/CropPicture" }, CloseCropPicture: function (base64Photo) { this.UserInfo.UserPhoto = base64Photo; this.dialogVisibleCop = false; },
参考文档
https://blog.csdn.net/XHL1314mmq/article/details/105815966
https://blog.csdn.net/qq_41389920/article/details/87967539