帝国cms是个人网站,网站建设超速云免费,自己做网站都要什么,led设计网站建设头像剪切上传 文章说明核心Api示例源码效果展示源码下载 文章说明 本文主要为了学习头像裁剪功能#xff0c;以及熟悉canvas绘图和转文件的相关操作#xff0c;参考教程#xff08;Web渡一前端–图片裁剪上传原理#xff09; 核心Api 主要就一个在canvas绘图的操作 context… 头像剪切上传 文章说明核心Api示例源码效果展示源码下载 文章说明 本文主要为了学习头像裁剪功能以及熟悉canvas绘图和转文件的相关操作参考教程Web渡一前端–图片裁剪上传原理 核心Api 主要就一个在canvas绘图的操作 context.drawImage(image, imgX, imgY, rectangleWidth, rectangleHeight, 0, 0, canvas.width, canvas.height); 以及canvas转为file对象的操作 let formData new FormData(); const file new File([blob], data.selectFileName, {type: data.selectFileType}) formData.append(“file”, file); 关于其中的绘制区域的大小缩放以及移动也算是一个小难点一般也有另一种裁剪区域风格即四条线风格可通过代码进行理解 示例源码 AvatarUpload.vue templatediv classcontainerdiv classimg-containerdiv classselect-file clickselectFile v-if!data.selectFilepjpg/png file with a size less than 5MBemclick to upload/em/p/divimg alt :srcdata.src classimg v-ifdata.selectFile draggablefalse:style{height : data.imgHeight }/div classrectangle v-ifdata.selectFile mousedowndragStart($event) mousemovechangePos($event)mousewheelwheel($event)/div/divcanvas width100 height100 classcanvas/canvasel-button typeprimary classupload-button clickuploadAvatar上传/el-button/div
/templatescript
import {onBeforeUnmount, onMounted, reactive} from vue;
import {axiosRequest, message} from /util/api;
import {MethodType} from /util/constant;export default {setup: function () {const data reactive({src: null,imgHeight: 300px,selectFile: false,selectFileName: ,selectFileType: ,});async function selectFile() {const pickerOpts {types: [{description: Images,accept: {image/*: [.png, .jpeg, .jpg],},},],excludeAcceptAllOption: true,multiple: false,};try {const fileHandle await window.showOpenFilePicker(pickerOpts);const file await fileHandle[0].getFile();data.selectFileName file.name;data.selectFileType file.type;const reader new FileReader();reader.readAsDataURL(file);reader.onload function (e) {data.src e.target.result;data.selectFile true;image new Image();image.src e.target.result;setTimeout(() {data.imgHeight image.height px;rectangle imgContainer.getElementsByClassName(rectangle)[0];rectangleWidth rectangle.clientWidth;rectangleHeight rectangle.clientHeight;context.drawImage(image, (image.width / 2 - rectangleWidth / 2), (image.height / 2 - rectangleHeight / 2), rectangleWidth, rectangleHeight, 0, 0, canvas.width, canvas.height);}, 0);};} catch (e) {if (!(e.name AbortError e.message The user aborted a request.)) {throw e;}}}let isDragging false;let mouseUpListener;let containerX;let containerY;let imgContainer;let imgWidth;let imgHeight;let rectangle;let initialX;let initialY;let rectangleWidth;let rectangleHeight;let imgX;let imgY;let headerHeight;let canvas;let context;let image;function dragStart(e) {isDragging true;containerX imgContainer.offsetLeft;containerY imgContainer.offsetTop;imgWidth imgContainer.clientWidth;imgHeight imgContainer.clientHeight;initialX e.offsetX;initialY e.offsetY;rectangle imgContainer.getElementsByClassName(rectangle)[0];rectangleWidth rectangle.clientWidth;rectangleHeight rectangle.clientHeight;}function changePos(e) {if (!isDragging) {return;}const x e.clientX - containerX - initialX rectangleWidth / 2;const y e.clientY - containerY - initialY - headerHeight rectangleHeight / 2;if (x rectangleWidth / 2 3 x imgWidth - rectangleWidth / 2 - 2) {imgX x - rectangleWidth / 2;rectangle.style.left x px;centerX imgX rectangleWidth / 2;context.drawImage(image, imgX, imgY, rectangleWidth, rectangleHeight, 0, 0, canvas.width, canvas.height);}if (y rectangleHeight / 2 3 y imgHeight - rectangleHeight / 2 - 4) {imgY y - rectangleHeight / 2;rectangle.style.top y px;centerY imgY rectangleHeight / 2;context.drawImage(image, imgX, imgY, rectangleWidth, rectangleHeight, 0, 0, canvas.width, canvas.height);}}onMounted(() {mouseUpListener () {isDragging false;}document.addEventListener(mouseup, mouseUpListener);const containerList document.getElementsByClassName(container);const container containerList[containerList.length - 1];headerHeight container.parentNode[getBoundingClientRect]().y;imgContainer container.getElementsByClassName(img-container)[0];canvas container.getElementsByClassName(canvas)[0];context canvas.getContext(2d);});onBeforeUnmount(() {document.removeEventListener(mouseup, mouseUpListener);});const gap 2;const minRange 20;let centerX;let centerY;function wheel(e) {if (!centerX) {centerX image.width / 2;}if (!centerY) {centerY image.height / 2;}if (e.deltaY 0) {if (rectangleWidth gap image.width || rectangleHeight gap image.height) {return;}if ((centerX - rectangleWidth / 2 - gap 0) || (centerY - rectangleHeight / 2 - gap 0)) {return;}rectangleWidth gap;rectangleHeight gap;rectangle.style.width rectangleWidth px;rectangle.style.height rectangleHeight px;} else {if (rectangleWidth - gap minRange || rectangleHeight - gap minRange) {return;}rectangleWidth - gap;rectangleHeight - gap;rectangle.style.width rectangleWidth px;rectangle.style.height rectangleHeight px;}context.drawImage(image, (centerX - rectangleWidth / 2), (centerY - rectangleHeight / 2), rectangleWidth, rectangleHeight, 0, 0, canvas.width, canvas.height);}function uploadAvatar() {if (!data.selectFile) {message(请先选择图片, info);return;}canvas.toBlob((blob) {let formData new FormData();const file new File([blob], data.selectFileName, {type: data.selectFileType})formData.append(file, file);axiosRequest(MethodType.post, /user/uploadAvatar, formData, (res) {message(res.data.msg, info);});}, data.selectFileType);}return {data,selectFile,dragStart,changePos,wheel,uploadAvatar,}}
}
/scriptstyle scoped
.container {margin: 0 auto;padding-top: 100px;width: fit-content;user-select: none;display: flex;justify-content: center;align-items: center;
}.img-container {position: relative;width: fit-content;
}.rectangle {width: 100px;height: 100px;border: 1px dashed #409eff;position: absolute;left: 50%;top: 50%;transform: translateX(-50%) translateY(-50%);z-index: 999;box-shadow: #888888 0 0 1px 1px;cursor: pointer;
}.select-file {width: 500px;height: 300px;border: 1px dashed #dcdfe6;border-radius: 20px;display: flex;justify-content: center;align-items: center;
}.select-file:hover {border: 1px dashed #409eff;cursor: pointer;
}.select-file p {font-size: 14px;color: #606266;
}.select-file p em {color: #409eff;font-style: normal;margin-left: 5px;
}.img {border-radius: 20px;border: 1px dashed #409eff;
}.canvas {margin-left: 100px;border: 1px dashed #409eff;float: left;border-radius: 50%;
}.upload-button {position: absolute;width: 180px;height: 50px;top: 460px;font-size: 20px;
}
/style效果展示 关于裁剪区域的风格设置为四条线可移动那种需要改动一些代码考虑后续补充 源码下载 参见Gitee链接WEB-OS-SYSTEM