由于在昨天的工作中,做且菜鸟新手的我当做到需要上传用户头像并及时显示的功能时,用到了FileReader
。虽然用法简单,但是还是做一下记录,记录自己的学习历程。
前言
以前的老方式上传图片到服务器进行编码,然后在存入数据库中,客户端要显示的话还要进行一次请求。
这样的老方式不仅效率低,而且非常不实用,必须使用异步方式的请求,才能增加用户体验效果
一、功能描述
功能描述就只有简单的以下几点,在实际过程中会涉及到一些头像显示的排版问题,浏览器兼容问题等,这里只是做一个简单的记录。
- 用户点击上传头像区域,上传头像并能正确显示
- 同时检测头像的大小与像素,如果不符合要求则不读取图片不显示,提示重新上传图片
- 当用户确认保存后,头像以编码的形式异步提交
二、实现头像区域显示及点击上传头像
- 在
div
区域中img
标签,用于头像上传及显示 - 编码
jquery
代码,实现点击上传头像
(1)头像上传及显示区域:
图片显示:
<div>
<img src="user.jpg" alt="User's Photo">
</div>
img
标签中的src
会接收图片的url
或者base-64
编码,只要正确就会显示图片。如下图:
(2)实现点击打开文件夹:
input[type= file]
标签:
<input type="file" id="image" accept="image/gif,image/jpeg,image/jpg,image/png,image/svg"/>
Jquery
代码:
//绑定input[type=file]点击事件,实现点击img区域就相当于点击input[type=file]
$('body').on('click','#photo',function(){
$('#image').trigger('click');
});
点击头像区域实则是input[type=file]
的点击上传,现在点击头像区域就可以打开文件夹,关键字trigger
实现了这个功能。
但此时必须要隐藏input[type=file]
,这样才会实现真正的点击头像上传,css代码实现隐藏input[type=file]
:
<style type="text/css">
#image{display:none !important;}
</style>
(3)实现点击更换:
上一步只是实现了点击头像区域,打开文件夹,并不能上传头像或者更换头像。还需要绑定change
事件:
$('body').on('change','#image',function(){
//获取文件对象
let file = $(this)[0].files[0];
console.log(file);
let fileReader = new FileReader(file);
//文件读取后的callback
fileReader.onload = function(){
console.log(this.result);
//base64编码存在于result中,也可以使用e.target.result $('img').attr('src',this.result)
}
//读文件
fileReader.readAsDataURL(file);
})
当我们点击更换头像时,头像以及被更换,img src
已经被更新为data:image/png;base64 code
我们查看file
对象以及头像编码
FileReader介绍
file
对象只是对文件进行描述,但是没不能够获得文件中的具体详细数据,这时我们需要HTML5 FileReader
读取文件中的数据。
(1)FileReader
方法介绍:
- readAsArrayBuffer(file):按字节读取文件内容,结果用ArrayBuffer对象表示
- readAsBinaryString(file):按字节读取文件内容,结果为文件的二进制串
- readAsDataURL(file) :读取文件内容,结果用data:url的字符串形式表示
- readAsText(file, encoding): 按字符读取文件内容,结果用字符串形式表示
- abort(): 终止文件读取操作
图片一般都用
readAsDataURL
方法读取,文本形式的一般用readAsText
,但此时需要注意编码.
(2)FileReader
事件介绍:
- onabort:当读取操作被中止时调用
- onerror: 当读取操作发生错误时调用
- onload:当读取操作成功完成时调用
- onloadend: 当读取操作完成时调用,无论成功或失败
- onloadstart:当读取操作开始时调用
- onprogress:在读取数据过程调用,可以用来显示大文件读取进度条等
$('body').on('change','#image',function(){
//获取文件对象
let file = $(this)[0].files[0];
console.log(file);
let fileReader = new FileReader(file);
let count = 0;
//文件读取后的callback
fileReader.onload = function(){
console.log('读取成功');
$('img').attr('src',this.result)
}
//文件读取开始时调用
fileReader.onloadstart = function(){
console.log("开始加载")
}
//文件读取结束时调用
fileReader.onloadend= function(){
console.log("加载结束")
}
//文件读取过程,进度显示
fileReader.onprogress = function(){
count++;
console.log("加载中"+count+'......')
}
//读文件
fileReader.readAsDataURL(file);
})
控制台中清楚地显示:
三、实现头像大小/像素验证
这里就需要到javascript
的Image
对象来获取头像的像素(height/width
)与大小(size
)等属性。
Image对象介绍
之前的无论是file对象
还是FileReder
对象都没有具体记录头像的大小与像素,这里的size
是以byte
为单位的,并不是我们要的头像大小
下面主要介绍将file
对象转为Image
对象,具体的Image
用法不做详细介绍(主要参考HTML DOM Image 对象)
fileReader.onload = function(e){
var imageData = e.target.result;
$('img').attr('src',imageData)
//创建Image对象
var image = new Image();
//加载读取图片Image
image.onload=function(){
var width = image.width;
var height = image.height;
var size = file.size/1024;//这里单位是K
console.log('width: '+image.width, 'height: '+image.height)
console.log('src: '+image)
console.log('size: 'file.size)
}
//将FileReader编码给Image对象的src值
image.src = imageData;
}
注意三点细节:
Image
对象的属性要在onload
加载后调用,才能正确显示,否则报错Image
对象的创建及操作必须在FileReader onload = function(){}
中,不然无法src
赋值,因为file
对象无法编码base64
- 头像的大小
file.size
就可以获得,但是需要转换为M/K
形式
Console控制台输出了图片的真是高度与长度、大小。以及Image src
的元素对象
我们先查看下user.jpeg
的像素与大小:
//定义头像的像素范围与大小
var MAX_WIDTH = 200;
var MAX_HEIGHT = 200;
var MAX_SIZE = 20*1024; //大小为20K
.....
//验证图片大小
if(size > MAX_SIZE){
//错误提示
console.log('头像不能大于20k')
return false;
}
//像素验证
if (width > MAX_WIDTH && height > MAX_HEIGHT) {
//错误提示
console.log('头像应在200*200')
return false;
}
//验证通过后才更换头像,同时ajax异步上传
$('img').attr('src',imageData)
//模拟ajax 异步上传
console.log('上传成功.....')
当我们传入user
头像时候控制台输出,并且头像不会被更新:
当我们传入qq
头像时控制台输出上传成功,且头像会被更新:
经过学习总结(注意)以下三点:
- 一般来说我们只需要验证头像的大小或者验证头像的像素,不会两个同时验证。
FileReader
与Image
部分较低IE
版本并不支持,所以一开始就应该准备判断浏览器是否支持,但这里不做介绍- 当然上传头像的相关工具
github
有很多,这里只是抛砖引玉,日后接触到更好的工具会再次记录