图片上传预览场景基本处处可见,朋友圈发动态配图,身份验证及头像更新,莫过如斯。
原由
最近在研究twitter PC网站的时候,在个人中心的主页,设置个人的背景图的时候,发现twitter有个非常好的设计,那就是用户在更改背景墙图片的时候,它根本不是先上传图片,而是在本地预览及编辑图片,待用户点击保存后,才上传图片,可以说是非常省流量的啦。然后,我在玩知乎的时候貌似它是先上传,然后预览的,为啥不学twitter这样做呢?于是乎,我就研究了下图片预览的几种方式,跟大家一起分享下。
介绍几个不常见的BOM对象
URL对象
-
URL对象是浏览器的原生对象,可以用来构造、解析及编码URL。一般情况下,通过window.URL可以拿到这个对象。
<a>
元素及<area>
元素都部署了这个接口。也就是说,它们的 DOM 节点对象可以使用 URL 的实例属性和方法。var a = document.createElement('a'); a.href = 'https://www.baidu.com?search=bat'; console.log(a.hostname); // www.baidu.com console.log(a.search); // ?search=bat
上面代码中,a是
<a>
元素的 DOM 节点对象。可以在这个对象上使用 URL 的实例属性,比如hostname和search。 -
URL是一个构造函数,可以生成URL实例。它接受一个表示 URL 的字符串作为参数。如果参数不是合法的 URL,会报错。
var url = new URL('http://www.example.com/index.html'); url.href // "http://www.example.com/index.html"
如果参数是另一个 URL 实例,构造函数会自动读取该实例的href属性,作为实际参数。
如果 URL 字符串是一个相对路径,那么需要表示绝对路径的第二个参数,作为计算基准。 -
实例属性
URL 实例的属性与Location对象的属性基本一致,返回当前 URL 的信息。
- URL.href:返回整个 URL
- URL.protocol:返回协议,以冒号:结尾
- URL.hostname:返回域名
- URL.host:返回域名与端口,包含:号,默认的80和443端口会省略
- URL.port:返回端口
- URL.origin:返回协议、域名和端口
- URL.pathname:返回路径,以斜杠/开头
- URL.search:返回查询字符串,以问号?开头
- URL.searchParams:返回一个URLSearchParams实例,该属性是Location对象没有的
- URL.hash:返回片段识别符,以井号#开头
- URL.password:返回域名前面的密码
- URL.username:返回域名前面的用户名
-
静态方法
- URL.createObjectURL()
URL.createObjectURL
方法用来为上传/下载的文件、流媒体文件生成一个URL
字符串。这个字符串代表了File
对象或Blob
对象的URL
。
URL.createObjectURL
方法用来为上传的文件生成一个 URL 字符串,作为元素的图片来源。注意,每次使用URL.createObjectURL
方法,都会在内存里面生成一个 URL 实例。如果不再需要该方法生成的 URL 字符串,为了节省内存,可以使用URL.revokeObjectURL()方法释放这个实例。 - URL.revokeObjectURL()
URL.revokeObjectURL
方法用来释放URL.createObjectURL
方法生成的 URL 实例。它的参数就是URL.createObjectURL
方法返回的 URL 字符串。
- URL.createObjectURL()
那么,大家关心的一个问题就是它的兼容性问题了,可以说移动端基本上是没啥问题的啦。除了个别的(IE,你瞅我干啥);
FileReader对象
FileReader
对象呢,在此不再赘述,因为一谈到图片上传,那必须要用到的。具体可以参看MDN的API文档了FileReader。
这个对象的兼容性,基本上也不用怎么考虑。除非个别的如IE6-9等等。
实例演示图片预览的几种方法
经过上述对两个对象的了解,那么大家可能知道,我们预览可能会跟这两个对象有关,毋庸置疑,那是必须要的。
<!--html-->
<img id="preview" src="" />
<input type="file" id="select" accept="iamge/png,iamge/jpeg,image/jpg" />
var preview = document.getElementById('preview'),
select = document.getElementById('select');
select.addEventListener('change', function fileInput (e) {
if (!this.files.length) return
var file = this.files[0];
previewImage(preview, file);
}, false);
- 第一种,也就是twttier使用的方式:
function previewImage (target, file) {
try {
var src = window.URL.createObjectURL(file);
target.onload = function () {
window.URL.revokeObjectURL(this.src);
};
target.src = src;
} catch (e) {
throw new Error('browser doest not support URL')
}
}
- 第二种,使用
FileReader
对象readAsDataURL
方法:
function previewImage (target, file) {
try {
var fileReader = new FileReader();
fileReader.onload = function (e) {
target.src = e.target.result
};
fileReader.readAsDataURL(file);
} catch (e) {
throw new Error('browser doest not support FileReader')
}
};
- 第三种,针对IE的,经了解,在IE7-11下,文件上传地址为本地的绝对路径地址,因此可一直直接将图片路径直接设置为input的值
select.addEventListener('change', function fileInput (e) {
if (!this.files.length) return
// 具体要在IE浏览器验证下
preivew.src = this.value;
}, false);
最后,如果你如果觉得我的文章不错的话,麻烦关注下我的个人公众号【前端汇聚】。