仿知乎头像上传

啥都不说, 直接先来一张效果图……

头像上传效果图

小伙伴们,别急,咱们先来分析一下主要功能点:

  1. 图片预览
  2. 图片拖拽
  3. 图片缩放
  4. 图片裁剪

图片预览

图片预览的功能技术方案是将用户的图片文件转成Base64编码并设置到<img>标签的src属性,获取图片文件的Base64编码需要通过HTML5的新特性FileReader,具体代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
getImgBase64: function(imgFile, cb){
if(!window.FileReader){
alert('系统暂不支持针对你的浏览器的文件上传功能,建议使用最新版的Chrome!');
return false;
}
var reader = new FileReader();
reader.onload = function(){
cb && cb(reader.result);
};
reader.readAsDataURL(imgFile);
return true;
}

图片拖拽

图片拖拽的功能需要借助鼠标事件mousedown, mousemove, mouseup,这里贴出mousemove里的处理:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
$(document).on('mousemove', function(e){
e.preventDefault();
var $thumb = $('.slider-thumb');
if($thumb.hasClass('moving')){
// 调整大小
var left = parseFloat($thumb.css('left'));
if(self.lastPosition){
var max = $thumb.siblings('.line').width() - $thumb.width();
(e.pageX >= self.lastPosition.x)
? (left >= max ? left = max : left += (e.pageX - self.lastPosition.x))
: (left <= 0 ? left = 0 : left += (e.pageX - self.lastPosition.x));
$thumb.css('left', left);
}
self.currentRadio = left / $thumb.siblings('.line').width() + 1;
self.resizeImg(self.currentRadio);
}
var $imgs = $('#avatarEditorDialog').find('img');
if($imgs.hasClass('moving')){
// 移动图片位置
var left = parseFloat($imgs.css('left'));
var top = parseFloat($imgs.css('top'));
var width = parseFloat($imgs.css('width'));
var height = parseFloat($imgs.css('height'));
if(self.lastPosition){
var leftMin = -(width - BASE - 30);
var topMin = -(height - BASE - 30);
(e.pageX < self.lastPosition.x)
? (left <= leftMin ? left = leftMin : left += (e.pageX - self.lastPosition.x))
: (left >= 30 ? left = 30 : left += (e.pageX - self.lastPosition.x));
(e.pageY < self.lastPosition.y)
? (top <= topMin ? top = topMin : top += (e.pageY - self.lastPosition.y))
: (top >= 30 ? top = 30 : top += (e.pageY - self.lastPosition.y));
$imgs.css({
left: left,
top: top
});
}
}
self.lastPosition = {
x: e.pageX,
y: e.pageY
};
});

代码中可以看出,图片拖拽也是有边界的,计算最小的lefttop值。

图片缩放

图片缩放很简单,主要在宽高比固定的条件下,调整图片的宽度和高度。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
resizeImg: function(radio){
var $imgs = $('#avatarEditorDialog').find('img');
var height = $imgs.height();
var width = $imgs.width();
if(height > width){
$imgs.css({
width: BASE * radio,
height: (BASE * height / width) * radio,
top: -((BASE * height / width) * radio - 310) / 2,
left: -(BASE * radio - 310) / 2
});
}else{
$imgs.css({
height: BASE * radio,
width: (BASE * width / height) * radio,
top: -(BASE * radio - 310) / 2,
left : -((BASE * width / height) * radio - 310) / 2
});
}
}

图片裁剪

这里的裁剪工作是在前端完成的,需要借助Canvas的一些接口。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var canvas = document.createElement('canvas');
canvas.id = 'avatarCanvas';
var ctx = canvas.getContext('2d');
var $img = $('.avatar-editor-window-inner img');
var originalWidth = parseFloat($img.attr('data-original-width'));
var originalHeight = parseFloat($img.attr('data-original-height'));
var nWidth = $img.width();
var nHeight = $img.height();
var x = (30 - parseFloat($img.css('left'))) * originalWidth / nWidth;
var y = (30 - parseFloat($img.css('top'))) * originalHeight / nHeight;
canvas.width = BASE * originalWidth / nWidth;
canvas.style.width = canvas.width;
canvas.height = BASE * originalHeight / nHeight;
canvas.style.height = canvas.height;
ctx.drawImage($img[0], x, y, canvas.width, canvas.height, 0, 0, canvas.width, canvas.height);
var avatar = canvas.toDataURL($img.attr('src').match(/data:(.*);base64/)[1] || 'image/jpg');

drawImage方法的功能是将图片上的某个点作为锚点,绘制指定的宽度和高度到Canvas标签。

完整的demo代码请移步至brucewar/avatar-upload

有心的读者可能已经发现,知乎的头像上传功能已经换了一种实现方案。不错,这还是之前的方案,通过上下两张图片实现预览时的边界半透明效果。

Enjoy it? Donate me!您的支持将鼓励我继续创作!

热评文章