作移动端的时候,各位可能会遇到用户上传头像,而前端的input:file,若是上传正方形图片还好,可是若是是矩形的话,在头像的显示这块,就会显的很不和谐。前端
前端跟进矩形的图片,实现裁剪成正方形,并把裁剪后的文件上传给后台。canvas
1.初始页面以下,点击中间默认头像触发input:file点击,弹出选择文件框.this

2.开始选择照片,以下,为选择的照片,和选择照片后的效果图:3d


3.此时图片的高度大于宽度,所以能够上下滚动,选择想要裁剪的范围,而后点击选取(下图从地铁导航处开始裁剪)。
code


此时,已经裁剪到正方形图片,能够从新拍摄或者上传给后台。component
下面是代码cdn
setPhoto(e) {//对图片尺寸作出限制并设置压缩尺寸
let _this = this;
let file = e.target.files[0];
if (!file) return ''
//大于6兆,不容许上传
if (file.size > this.maxSize * 6) {
return; this.$toast('图片过大,不能大于6M')
}
if (file.size > this.maxSize * 3) {//this.maxSize 为1024 * 1024,设置的一张照片最后
this.ratio = 0.5;
} else if (file.size > this.maxSize * 4) {
this.ratio = 0.4;
}
Lrz(file, { width: 1024, quality: this.ratio })
.then((rst) => { //这里使用Lrz,防止图片选中后旋转,若是没有这个问题,也能够不使用Lrz,直接把this.file转换为bolb对象的图片显示出来
// 把处理的好的图片给用户看看呗
// _this.$refs['avatar_img'].src = rst.base64;
_this.$refs['clip_avatar'].src = rst.base64;
_this.$nextTick(() => {
_this.avater_width_larger_height = _this.$refs['clip_avatar'].height < _this.$refs['clip_avatar'].width
})
_this.show_clip_img = true;
return rst;
}).then((rst) => {
this.file= rst.file;
})
},
checkClip(e) {//滑动后点击选取触发该方法,获取滚动的x和Y的距离传给 setPhotoCanvas,以便canvas裁剪。
let sTop = this.$refs['clip_img'].scrollTop;
let sLeft = this.$refs['clip_img'].scrollLeft;
this.setPhotoCanvas(sTop, sLeft);
},
setPhotoCanvas(sTop, sLeft) {
let reader = new FileReader();
reader.onloadend = (e) => {
let img = new Image();
img.onload = () => {
let w = Math.min(this.maxWidth, img.width);
let h = img.height * (w / img.width);
let [sw, sh, short, sx, sy] = [img.width, img.height, 0, 0, 0, 0]
if (w < h) {
short = w;
sy = (sTop / document.body.clientWidth) * img.width//这里头像裁剪的时候,宽度为屏幕的宽度,所以document.body.clientWidth。若是正方形的宽度不是屏幕宽度,这里和sx的获取都须要替换。
sh = sw;
} else { //w>h
short = h;
sx = (sLeft / document.body.clientWidth) * img.height
sw = sh;
}
let canvas = document.createElement('canvas');
let ctx = canvas.getContext('2d');
// 设置 canvas 的宽度和高度
canvas.width = short;
canvas.height = short;
ctx.drawImage(img, sx, sy, sw, sh, 0, 0, short, short);
let base64 = canvas.toDataURL('image/png', this.ratio);
// 插入到预览区
this.$refs[ 'avatar_img'].src = base64;
this.show_clip_img = false;
this.file = this.dataURItoBlob(base64);
console.log('size-------------------' + this.file.size)
};
img.src = e.target.result;
}
reader.readAsDataURL(this.file);
},
dataURItoBlob: function(dataURI) {//把用canvas获得的base64图片转换为二进制大对象以便传给后台
// convert base64/URLEncoded data component to raw binary data held in a string
let byteString;
if (dataURI.split(',')[0].indexOf('base64') >= 0) {
byteString = atob(dataURI.split(',')[1]);
} else {
byteString = unescape(dataURI.split(',')[1]);
}
// separate out the mime component
let mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0];
// write the bytes of the string to a typed array
let ia = new Uint8Array(byteString.length);
for (let i = 0; i < byteString.length; i++) {
ia[i] = byteString.charCodeAt(i);
}
return new Blob([ia], { type: mimeString });
},