头像修改功能 包含ios旋转图片 但是旋转后没遮罩, 正常图片可以显示遮罩 宽高不规则图片没做控制 遮罩框可以拖动

时间:2023-03-09 15:44:09
头像修改功能 包含ios旋转图片 但是旋转后没遮罩, 正常图片可以显示遮罩  宽高不规则图片没做控制 遮罩框可以拖动

https://blog.****.net/wk767113154/article/details/77989544  参考资料

<template>
<div id="profile" class="has-top">
<!-- <v-header title="我的资料"></v-header> -->
<!-- <div class="section" @click="changeAvatar()">
<mt-cell class="no-line" title="头像" is-link>
<v-image :src="userInfo.avatar" avatar class="circle60 mt_mb_10" />
</mt-cell>
</div> -->
<div class="box">
<div ref="cvs">
<canvas id="canvas" width="0" height="0"></canvas>
</div>
<div class="btn" @click="confirmBtn()">
确认
</div>
<div style="display:none">
<canvas id="preview" :width="cvw" :height="cvw"></canvas>
</div>
</div>
<div class="section">
<div class="head-pic">
<span class="left">头像</span>
<input type="file" class="tx-file" @change="handleFileChange" accept="image/*">
<div v-if="txStatus">
<div v-if="!defaultPic">
<img src="../../assets/images/account/default_avatar.png" alt="">
</div>
<div v-else>
<img :src="defaultPic" alt="">
</div>
</div>
<div v-else>
<img :src="successPic" alt="">
</div> <!-- <v-image :src="userInfo.avatar" avatar class="mt_mb_10" /> -->
</div>
<mt-cell title="昵称" :value="nickName" is-link :to="{path:'/user/edit-nickname'}" />
<mt-cell title="管理收货地址" is-link :to="{path:'/address/list?form=profile'}" />
<!-- <div class="mint-cell" @click="bindPhone()">
<span class="mint-cell-mask"></span>
<div class="mint-cell-wrapper">
<div class="mint-cell-title"><span class="mint-cell-text">{{userInfo.phone ? '当前' : ''}}绑定手机</span></div>
<div class="mint-cell-value is-link"><span>{{phone}}</span></div>
</div>
<i class="mint-cell-allow-right"></i>
</div>
<mt-cell :title="state.password + '密码'" :value="state.text" is-link :to="{path: state.url}" /> --> <!-- <mt-cell title="管理收货地址" is-link :to="{path:'/address/list'}" /> -->
<!--
<div class="mint-cell" @click="bindBank()">
<span class="mint-cell-mask"></span>
<div class="mint-cell-wrapper">
<div class="mint-cell-title"><span class="mint-cell-text">绑定银行卡</span></div>
<div class="mint-cell-value is-link"><span>{{bank.accountStatus||'未绑定'}}</span></div>
</div>
<i class="mint-cell-allow-right"></i>
</div> -->
</div>
<div class="section mt10">
<template v-if="invitor">
<mt-cell title="我的分享人" :to="{path:'/user/invitor'}" :value="invitor.nickName" is-link/>
</template>
<template>
<mt-cell title="账户与安全" :to="{path:'/account'}" is-link/>
</template>
</div>
<div class="section mt10">
<!-- <div class="mint-cell" @click="onContact()">
<span class="mint-cell-mask"></span>
<div class="mint-cell-wrapper">
<div class="mint-cell-title"><span class="mint-cell-text">联系客服</span></div>
</div>
<i class="mint-cell-allow-right"></i>
</div> -->
<mt-cell title="版本号" value="1.0.1"/>
</div>
<div class="logout" @click="logout()">
退出登录
</div>
</div>
</template>
<script type="text/javascript">
import Config from '../../config.js';
import UserService from '../../services/UserService.js';
import BankService from '../../services/BankService.js';
import WeChatService from '../../services/WeChatService.js';
import CsService from '../../services/CsService.js';
import { MessageBox } from 'mint-ui';
import axios from 'axios';
import EXIF from 'exif-js'
export default {
initWechat: true,
data() {
return {
defaultPic: '',
successPic: '',
txStatus: true,
phone: '',
nickName: '',
userInfo: {},
invitor: undefined,
bank: {},
config: null,
hasPassword: false,
state: {
password: '',
text: '',
url: '/user/edit-password'
},
canvas: null,
ctx: null,
preview: null,
ctxpreview: null,
img: null,
btn: null,
imgdata: null, //选中区域内容
point: null,
flag: false,
cvw:0,
orientation: null,
isIos: false,
lastX: null,
lastY: null,
disX: null,
disY: null
}
},
methods: {
logout() {
UserService.logout(this);
},
handleFileChange(ev) {
// WeChatService.uploadImage(this, (image) => {
// UserService.updateAvatar(this, image, () => {
// this.showMessage('更新头像成功');
// this.userInfo.avatar = image;
// });
// });
var _this = this
// let params = new FormData()
// let imgFile = ev.target.files[0]
// params.append('file', imgFile);
// params.append('version', '1.0');
/* 图片裁剪 */
_this.img = new Image() var reader = new FileReader()
var file = ev.target.files[0]
if(!file) {
return false
}
document.querySelector('.box').style.display = 'block'
reader.readAsDataURL(file);
reader.onload = function(e) {
console.log(_this.img)
_this.img.src = e.target.result
_this.img.onload = function() {
_this.orientation = null EXIF.getData(_this.img, function () {
EXIF.getAllTags(this);
_this.orientation = EXIF.getTag(this, "Orientation");// 获取方向角
var degree = 0, drawWidth = _this.img.width, drawHeight = _this.img.height, width, height;
//以下改变一下图片大小
var cliWidth = Math.floor(document.documentElement.clientWidth)
var cliHeight = Math.floor(document.documentElement.clientHeight)
var maxSide = Math.max(drawWidth, drawHeight);
var tarSize = cliHeight
// if(drawWidth > drawHeight) {
// tarSize = cliWidth
// }else {
// tarSize = cliHeight
// }
if (maxSide > tarSize) {
var minSide = Math.min(drawWidth, drawHeight);
minSide = minSide / maxSide * tarSize;
maxSide = tarSize;
if (drawWidth > drawHeight) {
drawWidth = maxSide;
drawHeight = minSide;
} else {
if(minSide > cliWidth) {
drawHeight = cliWidth * drawHeight / drawWidth
drawWidth = cliWidth
}else{
drawWidth = minSide;
drawHeight = maxSide;
}
}
}
else{
drawHeight = cliWidth * drawHeight / drawWidth
drawWidth = cliWidth
} _this.canvas.width = width = drawWidth;
_this.canvas.height = height = drawHeight;
switch (_this.orientation) {//横屏竖屏转化
//横屏拍摄,此时home键在左侧
case 3:
degree = 180;
drawWidth = -width;
drawHeight = -height;
break;
//竖屏拍摄,此时home键在下方(正常拿手机的方向)
case 6: _this.canvas.width = height;
_this.canvas.height = width;
console.log(_this.canvas.width,_this.canvas.height)
degree = 90;
drawWidth = width;
drawHeight = -height;
break;
//竖屏拍摄,此时home键在上方
case 8:
_this.canvas.width = height;
_this.canvas.height = width;
degree = 270;
drawWidth = -width;
drawHeight = height;
break;
} _this.ctx.rotate(degree* Math.PI/180); _this.ctx.clearRect(0,0,_this.canvas.width,_this.canvas.height);
_this.ctx.drawImage(_this.img, 0, 0, drawWidth, drawHeight);
_this.ctx.save()
_this.ctx.fillStyle = 'rgba(0,0,0,0.5)'
_this.ctx.fillRect(0,0,_this.canvas.width,_this.canvas.height)
_this.ctx.restore()
// if(cliHeight > drawHeight) {
// _this.$refs.cvs.style.marginTop = (cliHeight-drawHeight)/2 + 'px'
// } // _this.drawcenter()
_this.ctx.save()
_this.ctx.fillStyle = 'rgba(0,0,0,0.5)'
_this.ctx.fillRect(0,0,_this.canvas.width,_this.canvas.height)
_this.ctx.restore()
_this.lastX = _this.canvas.width / 2
_this.lastY = _this.canvas.height / 2
_this.drawtop((_this.canvas.width - _this.cvw)/2,(_this.canvas.height - _this.cvw)/2,drawWidth,drawHeight)
// 移动canvas
_this.canvas.ontouchstart = function(e) {
e.preventDefault();
if(e.touches.length == 1) {
_this.flag = true
_this.point = _this.windowToCanvas(_this.canvas,e.touches[0].clientX,e.touches[0].clientY)
_this.disX = _this.point.x - _this.lastX
_this.disY = _this.point.y - _this.lastY
_this.point.x = _this.point.x - _this.disX
_this.point.y = _this.point.y - _this.disY _this.ctx.clearRect(0,0,_this.canvas.width,_this.canvas.height);
_this.ctx.drawImage(_this.img, 0, 0, drawWidth, drawHeight);
_this.ctx.save()
_this.ctx.fillStyle = 'rgba(0,0,0,0.5)'
_this.ctx.fillRect(0,0,_this.canvas.width,_this.canvas.height)
_this.ctx.restore()
_this.drawtop(_this.point.x-(_this.cvw/2),_this.point.y-(_this.cvw/2),drawWidth,drawHeight)
} }
_this.canvas.ontouchmove = function(e) {
e.preventDefault();
if(_this.flag) {
_this.point = _this.windowToCanvas(canvas,e.changedTouches[0].clientX,e.changedTouches[0].clientY)
// console.log(point.x + ' - ' + point.y)
_this.lastX = _this.point.x - _this.disX
_this.lastY = _this.point.y - _this.disY
_this.point.x = _this.point.x - _this.disX
_this.point.y = _this.point.y - _this.disY
_this.ctx.clearRect(0,0,_this.canvas.width,_this.canvas.height);
_this.ctx.drawImage(_this.img, 0, 0, drawWidth, drawHeight);
_this.ctx.save()
_this.ctx.fillStyle = 'rgba(0,0,0,0.5)'
_this.ctx.fillRect(0,0,_this.canvas.width,_this.canvas.height)
_this.ctx.restore()
_this.drawtop(_this.point.x-(_this.cvw/2),_this.point.y-(_this.cvw/2),drawWidth,drawHeight)
}
}
_this.canvas.ontouchend = function(e) {
//将鼠标状态释放
_this.flag = false
_this.point.x = _this.point.x
_this.point.y = _this.point.y
_this.imgdata = _this.ctx.getImageData(_this.point.x-(_this.cvw/2),_this.point.y-(_this.cvw/2),_this.cvw,_this.cvw)
_this.ctxpreview.putImageData(_this.imgdata,0,0)
}
// if(drawWidth < cliWidth) {
// if(drawWidth < drawHeight) {
// //_this.drawtop(drawWidth/2-_this.cvw/2,drawHeight/2-_this.cvw/2,drawWidth,drawHeight)
// _this.ctx.save()
// _this.ctx.beginPath()
// console.log(0,drawHeight/2-drawWidth/2,drawWidth,drawWidth)
// _this.ctx.rect(0,drawHeight/2-drawWidth/2,drawWidth,drawWidth)
// _this.ctx.closePath()
// _this.ctx.clip()
// //在该图层绘制原图
// _this.ctx.drawImage(_this.img,0, 0,drawWidth,drawHeight)
// console.log(0,drawHeight/2-drawWidth/2,drawWidth,drawWidth)
// _this.imgdata = _this.ctx.getImageData(0,drawHeight/2-drawWidth/2,drawWidth,drawWidth)
// console.log(0,drawHeight/2-drawWidth/2,drawWidth,drawWidth)
// _this.ctxpreview.putImageData(_this.imgdata,0,0)
// _this.ctx.restore()
// }else{
// _this.ctx.save()
// _this.ctx.beginPath()
// _this.ctx.rect(drawWidth/2-drawHeight/2,0,drawHeight,drawHeight)
// _this.ctx.closePath()
// _this.ctx.clip()
// //在该图层绘制原图
// _this.ctx.drawImage(_this.img,0, 0,drawWidth,drawHeight)
// _this.imgdata = _this.ctx.getImageData(drawWidth/2-drawHeight/2,0,drawHeight,drawHeight)
// _this.ctxpreview.putImageData(_this.imgdata,0,0)
// _this.ctx.restore()
// } // }else{
// _this.drawtop(cliWidth/2-(_this.cvw/2),cliHeight/2-(_this.cvw/2),drawWidth,drawHeight)
// } //_this.drawtop((drawWidth/2-_this.cvw/2),(drawHeight/2-_this.cvw/2),drawWidth,drawHeight) }) // _this.canvas.width = Math.floor(document.documentElement.clientWidth)
// _this.canvas.height = Math.floor(document.documentElement.clientHeight) // _this.ctx.clearRect(0,0,_this.canvas.width,_this.canvas.height);
// //第一层将图像绘制到canvas
// _this.ctx.drawImage(_this.img,(_this.canvas.width-_this.img.width)/2,(_this.canvas.height-_this.img.height)/2,_this.img.width,_this.img.height) }
// console.dir(e.target.result)
}
},
confirmBtn() {
var _this = this
document.querySelector('.box').style.display = 'none'
//console.log(preview.toDataURL("image/png")) let params = new FormData()
let dataURL = this.preview.toDataURL("image/png")
let blob = this.dataURItoBlob(dataURL);
params.append('file', blob);
params.append('version', '1.0'); axios.post(process.env.BASE_API + 'ddmallapi/upload/uploadImage', params, {
headers:{'Content-Type':'multipart/form-data'}
}).then(function(res) {
console.log(res)
if(res.data.data.imgUrl) {
_this.txStatus = false
_this.successPic = res.data.data.imgUrl;
let paramSave = new FormData()
paramSave.append('headImage',res.data.data.imgUrl)
axios.post(process.env.BASE_API + 'ddmallapi/user/changeHead?version=1.0', paramSave, {
headers:{'Content-Type':'application/x-www-form-urlencoded'}
}).then(function(res) {
// if(res.data.code === 0) {
// UserService.getInfo(_this,(res) => {
// console.log(res.data.data.headImage)
// });
// } }).catch(function(err) {
console.log(err)
})
}else{
_this.showError(res.data.message);
}
}).catch(function(err) {
console.log(err)
})
},
onContact() {
CsService.showCsView();
},
bindPhone() {
if (!this.hasPassword) {
let toast = Config.toast.filter(item => item.id == 'noLogin')[0];
this.showConfirms(toast.title, toast.message, () => {
this.$router.push({
path: '/find-password',
query: {
redirect: location.pathname,
set: true
}
})
}, null, '去设置', '取消');
return;
} if (!this.userInfo.phone) {
this.$router.push({ path: '/bind/phone' });
return;
}
this.$router.push({ path: '/user/edit-phone' });
},
checkPassword() {
UserService.checkPassword(this, (res) => {
if (res.code == 1) {
this.hasPassword = true;
this.state.password = '修改';
} else {
this.state.password = '设置';
this.state.text = '去设置';
this.state.url = '/find-password'
this.state.url += '?set=true&redirect='+location.pathname
}
})
},
drawcenter() {
//第二层 在图片上绘制半透明遮罩
this.ctx.save()
this.ctx.fillStyle = 'rgba(0,0,0,0.5)'
this.ctx.fillRect(0,0,this.canvas.width,this.canvas.height)
this.ctx.restore()
},
drawtop(x,y,drawWidth,drawHeight){
//第三层 局部高亮
this.ctx.save()
this.ctx.beginPath()
this.ctx.rect(x,y,this.cvw,this.cvw)
this.ctx.closePath()
this.ctx.clip()
//在该图层绘制原图
this.ctx.drawImage(this.img,0, 0,drawWidth,drawHeight)
this.imgdata = this.ctx.getImageData(x,y,this.cvw,this.cvw)
this.ctxpreview.putImageData(this.imgdata,0,0)
this.ctx.restore()
},
windowToCanvas(element,x,y) {
var box = element.getBoundingClientRect();
var cx = x - box.left
var cy = y - box.top
return {x:cx,y:cy}
},
dataURItoBlob(dataURI) {
var byteString = atob(dataURI.split(',')[1]);
var mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0];
var ab = new ArrayBuffer(byteString.length);
var ia = new Uint8Array(ab);
for (var i = 0; i < byteString.length; i++) {
ia[i] = byteString.charCodeAt(i);
}
return new Blob([ab], {type: mimeString});
}
},
created() {
this.checkPassword();
},
mounted() { this.canvas = document.getElementById('canvas')
this.preview = document.getElementById('preview')
this.ctx = this.canvas.getContext('2d')
this.ctxpreview = this.preview.getContext('2d')
this.btn = document.querySelector('.btn')
this.cvw = 300
this.$root.$on('user.info.update', (userInfo) => {
console.log(userInfo)
this.userInfo = userInfo.data; if (this.userInfo.phone) {
this.phone = this.userInfo.phone.substr(0, 3) + '****' + this.userInfo.phone.substr(7);
}
if (this.userInfo.nickName && this.userInfo.nickName.length > 7) {
this.nickName = this.userInfo.nickName.substr(0, 7) + '...';
} else {
this.nickName = this.userInfo.nickName
}
}); UserService.getInfo(this, (res) => {
if(res.headImage) {
this.defaultPic = res.headImage
}
});
UserService.getInvitor(this, (data) => {
this.invitor = data;
}, () => {});
}
}
</script>
<style>
.logout {
margin-top: 20px;
height: 45px;
text-align: center;
background: #fff;
line-height: 45px;
font-size: 16px;
color: #ff4646;
}
.mint-cell {
min-height: 44px;
}
.mint-cell-text {
font-size: 16px !important
}
.mint-cell-value > span {
font-size: 16px !important
}
.head-pic {
padding: 0 15px;
position: relative;
height: 50px;
border-bottom: 1px solid #f0f0f0;
}
.head-pic .tx-file{
position:absolute;
left: 0;
top: 0;
width: 100%;
height: 50px;
opacity: 0;
}
.head-pic img {
margin-top: 5px;
float:right;
width: 40px;
height: 40px;
border-radius: 50%;
}
.head-pic .left{
float: left;
font-size: 16px !important;
line-height: 50px;
}
.user-center-header .header-left{
margin-left: 0.7rem;
}
</style> <style scoped>
.box{
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
z-index: 111;
background: #333;
display: none;
overflow: hidden;
text-align:center;
}
.box .btn {
position: absolute;
width: 60px;
height: 30px;
right: 5px;
top: 5px;
z-index: 111;
background: #fff;
line-height: 30px;
text-align: center;
border-radius: 5px;
}
.box canvas{ }
</style>