写下这篇文章缘由是做这个功能属实是踩了很多坑...
话不多说,开讲!
引入vueCropper插件
// 安装
npm install vue-cropper@next
// 或者
yarn add vue-cropper@next
// 在页面引入
import "vue-cropper/dist/index.css";
import { VueCropper } from "vue-cropper";
elementPlus的上传组件
这里一个上传组件一个没有头像时候的默认头像,可以只复制el-upload的代码
<div
class="avatar flex-center-center"
@mouseenter="isShowAvatar = -1"
@mouseleave="isShowAvatar = 0"
>
<el-upload
class=""
:headers="headers"
:auto-upload="false"
action=""
:on-change="changeSize"
accept=".jpg,.png"
:on-success="onImageSuccess"
:on-error="onImageError"
v-if="isShowAvatar && userInfo.id == formData.id"
>
<div
class="modify-avatar tac cp"
:style="`background-color: ${themeColor};`"
>
<el-icon
:size="25"
color="#fff"
>
<Camera />
</el-icon>
</div>
</el-upload>
<el-avatar
v-else
:size="100"
:src="!userInfo.avatar ? 'https://cube.elemecdn.com/0/88/03b0d39583f48206768a7534e55bcpng.png'
: userInfo.avatar.includes('http')?userInfo.avatar:userInfo.baseURL+userInfo.avatar "
></el-avatar>
</div>
现在进入正题,上图片裁剪代码
html部分,这是一个el-dialog弹窗
<!-- 头像裁剪弹窗 -->
<el-dialog
v-model="centerDialogVisible"
title="裁剪头像"
width="60%"
align-center
>
<div class="cropper-content">
<div
class="cropper"
style="text-align:center"
>
<vueCropper
ref="cropper"
:img="option.img"
:outputSize="option.size"
:outputType="option.outputType"
:info="true"
:full="option.full"
:canMove="option.canMove"
:canMoveBox="option.canMoveBox"
:original="option.original"
:autoCrop="option.autoCrop"
:fixed="option.fixed"
:fixedNumber="option.fixedNumber"
:centerBox="option.centerBox"
:infoTrue="option.infoTrue"
:fixedBox="option.fixedBox"
:autoCropWidth="option.autoCropWidth"
:autoCropHeight="option.autoCropHeight"
/>
<div class="handle_btn">
<el-button
type="primary"
plain
@click="changeScale(1)"
>+ 放大</el-button>
<el-button
type="primary"
plain
@click="changeScale(-1)"
>- 缩小</el-button>
<el-button
type="primary"
plain
@click="rotateLeft"
>↺ 左旋转</el-button>
<el-button
type="primary"
plain
@click="rotateRight"
>↻ 右旋转</el-button>
</div>
</div>
</div>
<template #footer>
<span class="dialog-footer">
<el-button @click="centerDialogVisible = false">取消</el-button>
<el-button
type="primary"
@click="uploadAvatar"
> 确认 </el-button>
</span>
</template>
</el-dialog>
数据层
// 头像裁剪
const centerDialogVisible = ref(false);
//获取裁剪图片组件
const cropper = ref();
// 头像裁剪各项参数
const option = reactive({
img: "", // 裁剪图片的地址
info: true, // 裁剪框的大小信息
outputSize: 1, // 裁剪生成图片的质量
outputType: "jpg", // 裁剪生成图片的格式
canScale: true, // 图片是否允许滚轮缩放
autoCrop: true, // 是否默认生成截图框
canMoveBox: true, // 截图框能否拖动
autoCropWidth: 200, // 默认生成截图框宽度
autoCropHeight: 200, // 默认生成截图框高度
fixedBox: false, // 固定截图框大小 不允许改变
fixed: true, // 是否开启截图框宽高固定比例
fixedNumber: [1, 1], // 截图框的宽高比例
full: false, // 是否输出原图比例的截图
original: false, // 上传图片按照原始比例渲染
centerBox: false, // 截图框是否被限制在图片里面
infoTrue: true, // true 为展示真实输出图片宽高 false 展示看到的截图框宽高
});
css
.cropper-content {
.cropper {
width: auto;
height: 350px;
.handle_btn {
display: flex;
display: -webkit-flex;
justify-content: space-between;
padding: 10px 300px;
box-sizing: border-box;
}
}
}
现在就开始处理全部逻辑了
首先是el-upload的change事件,这一步一定要做,卡住了我很久...如果不将得到的文件url转换成base64,只要给option.img赋值就会报CORS跨域,还有一点el-upload里面的action一定不要写上传地址,不然也会也有报错
const changeSize = (UploadFile) => {
centerDialogVisible.value = true;
//这里将图片转化为base64位格式为图片进行裁剪
const reader = new FileReader();
reader.onload = (e) => {
//将图片绑定到裁剪组件的img中
option.img = e.target.result;
};
//拿到图片的base64
reader.readAsDataURL(UploadFile.raw);
};
最后一步就是确认裁剪操作了,这一步一定要用asyncawait,不然数据获取的会有问题,会显示promisepending,调上传接口的时候也要把headers带上,点击确认裁剪的时候我加了一个elementplus的loading动画,防止没上传完弹出就被用户x掉了
// 点击确认
const uploadAvatar = () => {
isLoading.value = true;
//上传头像并且点击了确认按钮 异步才能获取数据
cropper.value.getCropBlob(async (data) => {
let formData = new FormData();
formData.append("file", data, "avatar.jpg");
const res = await axios({
method: "post",
headers: {
"Access-Control-Allow-Origin": "*",
token: getToken(),
}, // 请求头
url: "/api/set/upload", //请求地址
data: formData,
});
if (res.data.code == 1) {
isLoading.value = false;
saveAvatar({ avatar: res.data.data.fullurl }).then((res2) => {
centerDialogVisible.value = false;
if (res2.data.code == 1) {
ElMessage.success("修改成功");
getBriefInfo();
isShowAvatar.value = 0;
userInfo.avatar = res.data.data.fullurl;
} else {
ElMessage.error("上传图片错误,请稍后重试");
}
});
} else {
isLoading.value = false;
}
});
};
附加一个放大缩小旋转的小功能
//图片缩放
const changeScale = (num) => {
num = num || 1;
cropper.value.changeScale(num);
};
//向左旋转
const rotateLeft = () => {
cropper.value.rotateLeft();
};
//向右旋转
const rotateRight = () => {
cropper.value.rotateRight();
};
loading动画,标签根部
数据层定义
let isLoading = ref(false);
总结:首先使用el-upload拿到图片地址,将图片url转换成base64,使用头像裁剪,最后调用upload上传接口,成功后调用保存图片即可
完结,撒花,以上代码有任何问题请私信踢我,或者评论区留言!!!!!!!!!!!