效果图
导入样式和js
<link rel="stylesheet" href="https://cdn.bootcss.com/cropperjs/2.0.0-alpha.1/cropper.css">
<script src="https://cdn.bootcss.com/cropperjs/2.0.0-alpha.1/cropper.js"></script>
html样式如下
<div class="messagePhoto">
<div class="leftChangePhoto">
<div class="changePhoto">
<p class="changePhotoshow">
<span class="changePhotoshowicon">
<img src="/public/src/viedo/update.png" alt="" srcset="">
</span>
<span class="changePhotoshowiconWords">
选择本地图片
</span>
</p>
<input type="file" onclick="changeUserOwnPhotos(this)">
<span id="sleteiupdatePhoto">
选择图片
</span>
</div>
<div class="btnchangeUserPhoto">
<span class="btnChangePhotoUserOwn">
复位
</span>
<span class="btnChangePhotoUserOwn">
旋转
</span>
<span class="btnChangePhotoUserOwn">
换向
</span>
<span class="btnChangePhotoUserOwn">
放大
</span>
<span class="btnChangePhotoUserOwn">
缩小
</span>
</div>
</div>
<div class="rightchangephotoShow">
<div class="imgshowupdate">
<div class="imgPhotoChangeshow">
<div class="imgshow">
<img src="/public/src/QQ图片20230227113456.jpg" alt="" srcset="" id="imgPhotoshowsUserown">
<p>
当前头像
</p>
</div>
</div>
</div>
</div>
<div class="userUpdatePhotobtn" onclick="changephotos()">
<span>
确定
</span>
</div>
</div>
scss
.messagePhoto {
width: 350px;
display: flex;
position: relative;
height: 200px;
padding-bottom: 10px;
justify-content: space-around;
}
.leftChangePhoto {
width: 4000px;
// height: 150px;
padding-right: 20px;
border-right: 1px solid rgb(166, 163, 163);
}
.rightchangephotoShow {
width: 120px;
margin-left: 10px;
}
.changePhoto {
padding-top: 10px;
padding-bottom: 10px;
width: 295px;
margin-top: 10px;
margin-bottom: 10px;
height: 172px;
background-color: #f1f2f5;
position: relative;
text-align: center;
input {
z-index: 20;
position: absolute;
width: 100%;
left: 11px;
bottom: -76px;
width: 151px;
opacity: 0;
}
#sleteiupdatePhoto{
position: absolute;
width: 100%;
left: 11px;
bottom: -76px;
width:151px;
left: -29px;
color: #8eb8e8;
}
}
.changemessagetitle {
padding-bottom: 10px;
position: relative;
border-bottom: 1px solid rgb(169, 168, 168);
}
.changePhotoshowicon {
width: 20px;
height: 20px;
img {
width: 20px;
height: 20px;
}
}
.changePhoto {
font-size: 16px;
}
.changePhotoshowiconWords {
position: relative;
top: -4px;
}
.changePhotoshow {
padding-top: 58px;
}
.imgPhotoChangeshow {
width: 150px;
padding-left: 20px;
position: absolute;
.imgshow {
margin-top: 10px;
width: 120px;
height: 120px;
// overflow: hidden;
border-radius: 50%;
text-align: center;
img {
width: 120px;
height: 120px;
border-radius: 50%;
}
p {
margin-top: 10px;
font-size: 12px;
}
}
}
.changePhotoTitle {
margin-top: 10px;
font-size: 15px;
color: rgb(142, 184, 232);
}
.userUpdatePhotobtn {
position: absolute;
bottom: -89px;
width: 175px;
text-align: center;
span {
font-size: 15px;
padding: 7px 20px;
border-radius: 6px;
border: 1px solid #8eb8e8;
}
}
js
//传入对象并且回显获取img
function changeUserOwnPhotos(obj) {
let parentUserPhoto = obj.parentNode;
obj.addEventListener("change", function () {
const { files } = this;
const changeFiles = files[0];
if (!changeFiles) {
return
}
if (document.getElementById('changeUserPhotoImg')) {
//先移除
let changeUserPhotoImg = document.getElementById('changeUserPhotoImg');
parentUserPhoto.removeChild(changeUserPhotoImg)
//并且将已经创建的cropper对象给它移除
cropper.destroy();
}
const allowedTypes = ['image/jpeg', 'image/png', 'image/gif'];
if (!allowedTypes.includes(changeFiles.type)) {
alerterror("请选择图片文件");
return;
}
let curChanggePhoto = document.createElement('img');
curChanggePhoto.id = 'changeUserPhotoImg';
parentUserPhoto.appendChild(curChanggePhoto);
curChanggePhoto.src = URL.createObjectURL(changeFiles);
changeuserPhgotoBasic()
changebtnClick()
})
}
var cropper
function changeuserPhgotoBasic() {
console.log(cropper);
if(!cropper==undefined){
cropper==undefined
}
//设置图片包括裁剪形式
cropper = new Cropper(document.getElementById('changeUserPhotoImg'), {
aspectRatio: 1 / 1,
preview: '.previewImg',
guides: false,
autoCropArea: 0.5,
movable: false,
dragCrop: true,
movable: true,
resizable: true,
scalable: false,
zoomable: true,
mouseWheelZoom: false,
touchDragZoom: false,
rotatable: true,
crop: function (e) {
let cas = cropper.getCroppedCanvas()
let base64 = cas.toDataURL('image/jpeg')
document.getElementById("imgPhotoshowsUserown").src = base64
}
})
}
function changebtnClick() {
if (!cropper) {
return
}
let btnChangeUserPhoto = document.getElementsByClassName('btnChangePhotoUserOwn')
// 旋转
btnChangeUserPhoto[1].onclick = function () {
cropper.rotate(90)
}
btnChangeUserPhoto[0].onclick = function () {
cropper.reset()
}
// 放大
btnChangeUserPhoto[2].onclick = function () {
cropper.zoom(2)
}
// 缩小
btnChangeUserPhoto[3].onclick = function () {
cropper.zoom(-2)
}
}
//将base64转化为blob对象
function changeUserOwnPhotoBtn(urlData) {
var bytes = window.atob(urlData.split(',')[1])
var ab = new ArrayBuffer(bytes.length)
var ia = new Uint8Array(ab)
for (var i = 0; i < bytes.length; i++) {
ia[i] = bytes.charCodeAt(i)
}
return new Blob([ab], { type: 'image/png' })
}
function changephotos() {
if (!document.getElementById('changeUserPhotoImg') && !cropper) {
alerterror('请先上传图片');
return
}
let fromdata = new FormData()
let cas = cropper.getCroppedCanvas()
let base64 = cas.toDataURL('image/jpeg')
//将其转化后的blob文件发给后端处理
fromdata.append('file', changeUserOwnPhotoBtn(base64), '测试.png');
axios({
url: '/userOwn/uploadUserPhoto',
method: 'post',
data:fromdata,
}).then(response => {
if(response.data.err==0){
alertSuccess('更新头像成功')
}
else if(response.data.err==-1){
alerterror("身份过期")
}
else{
alerterror('更新失败')
}
}).catch(err => {
res.send(err)
})
}
node端处理
const multipart = require('connect-multiparty')
const FormData = require('form-data')
const fs = require('fs')
var mult = multipart()//得到实例
router.post('/uploadUserPhoto', mult, (req, res) => {
//如果是多文件遍历即可
//如果不是多文件直接req.files.file.path即可
let formdata = new FormData()
for (let a in req.files) {
formdata.append('file', fs.createReadStream(req.files[a].path), req.files[a].originalFilename)//第二个是文件名
}
axios({
url: '/user/updateHeadImg',
method: 'post',
headers: {
token: req.session.token
}
,
data: formdata
})
.then(response => {
if (response.code == 200) {
res.send({
err: 0, msg: '更新成功'
})
}
else if (response.code == 401) {
res.send({
err: -1, msg: "登录过期"
})
}
else {
res.send({
err: -2, msg: "更新头像失败"
})
}
}).catch(err => {
res.send(err)
})
})
本文参考BUG不加糖这篇cropper 学长讲的很透彻
下周计划
下周主要还是写项目 还有一周就截止了 项目东西很多 慢慢来吧