这两天刚好有一位同事问我怎样作一个图片预览功能。做为现代人的咱们首先想到的固然是HTML5啦,其实HTML5作图片预览已是一个老生常谈的问题了。我在这里就简单说说其中相关的一些东西,固然会附上咱们的源码。在 HTML5 以前咱们作图片预览主流作法有两种,第一种是经过 Flash 插件来作预览,第二种是 Ajax 实现的假预览,也就是说选择图片文件后,图片其实已经异步上传到服务器,服务器处理后返回图片路径,前端获得响应结果作出处理从而使图片显示在界面上。而有了 HTML5 以后就能够强烈鄙视上面两种作法了。javascript
要作图片预览功能,就不得不介绍一下 FileReader,顾名思义,它是用来读取文件的。固然新东西总会有一些顽固派排斥的,咱们先来看看其兼容性如何(这不是本文讨论的重点)。css
PC端兼容列表html
移动端兼容列表 前端
兼容性的话你们根据本身的需求参考一下上面的对照表,咱们接着来看看 FileReader 的几个经常使用属性和经常使用方法java
属性web
方法canvas
废话很少说,咱们经过代码来更直观点认识上面的属性和方法。回归到需求,作一个图片预览功能。首先理一理咱们须要有的东西,第一要素固然是文件(文件选择器),第二固然是预览(容器)。浏览器
html 代码 (样式我顺手加上了)ruby
<!DOCTYPE html> <html> <head> <title>Cboyce-HTML5图片预览</title> <style type="text/css"> /*主容器*/ .container{ width: 90%; margin-top: 20px; } /*图片预览容器*/ .container .img-prev-container{ width: 200px; height: 100px; margin:10px auto; border:1px solid #ccc; } /*预览图片样式*/ .container .img-prev-container img{ width: 100%; height: 100%; } </style> </head> <body> <div class="container"> <div class="img-prev-container"> </div> <input type="file" value="请选择图片" id="fileSelecter" /> </div> </body> </html>
接下来该 FileReader 出场了服务器
window.onload = function(){ //触发 change 事件 GetDomById('fileSelecter').onchange = function(event){ //获取文件对象 var file = event.target.files[0]; //建立reader对象 var reader = new FileReader(); //读取完成后触发 reader.onload = function(ev){ //获取图片的url var _img_src = ev.target.result; console.log(_img_src) //添加预览图片到容器框 var img = document.createElement('img'); img.setAttribute('src',_img_src); GetDomById('img-perv-div').appendChild(img); } //获取到数据的url 图片将转成 base64 格式 reader.readAsDataURL(file); } } //简化 document.getElementById() 函数 function GetDomById(id){ return document.getElementById(id); }
细节注意:这里的图片格式默认转为 base64
补充说明:
event.target 属性,其特色在咱们的代码中其实不忙看出来 "捕获当前事件做用的对象",通俗点来说就是,谁触发了该事件,我就能经过该事件的 target 拿到谁。
其实上述代码还有一个小 bug "换图变成多图"。 请看下图
修复:改造 onload
reader.onload = function(ev){ //获取图片的url var _img_src = ev.target.result; //预览图的容器 var _img_container = GetDomById('img-perv-div') //添加预览图片到容器框 var _imgs = _img_container.getElementsByTagName('img'); //容器中没有则建立,有则修改 src 属性 if(!_imgs.lenght){ _imgs[0] = document.createElement('img'); _imgs[0].setAttribute('src',_img_src); _img_container.appendChild(_imgs[0]); }else{ _imgs[0].setAttribute('src',_img_src); } }
解决bug
上面咱们已经把基础功能给完成了,接下来咱们给该程序加个拓展--拖拽图片到预览框自动加载。 要完成该功能仍是得靠 HTML5 的 Drag 和 drop。若是你还搞不清楚咱们要作什么,那咱们先来看下最终效果。
在代码开始以前咱们先来了解两个实现该功能最为关键的事件。 1. dragover 拖拽一个对象到目标对象上面触发该事件 2. drop 拖放事件结束时触发。通俗来说就是当咱们拖拽一个对象到目标对象上后放开(松开鼠标左键)该对象的时候触发
接下来咱们来看下代码,这里也对以前的代码作出了一些改造
window.onload = function(){ //预览图的容器 var _img_container = getDomById('img-perv-div') //建立reader对象 var reader = new FileReader(); //触发 change 事件 getDomById('fileSelecter').onchange = function(event){ //获取文件对象 var file = event.target.files[0]; //读取完成后触发 reader.onload = function(ev){ //获取图片的url var _img_src = ev.target.result; //添加预览图片到容器框 showPrevImg(_img_container,_img_src); } //获取到数据的url 图片将转成 base64 格式 reader.readAsDataURL(file); } //添加拖放支持 _img_container.addEventListener('dragover',function(ev){ ev.preventDefault();//阻止默认事件。好比说Chrome是直接将图片用浏览器打开 },false) _img_container.addEventListener('drop',function(ev){ ev.preventDefault(); reader.onload = function(ev){ //获取图片的url var _img_src = ev.target.result; //图片预览处理 showPrevImg(_img_container,_img_src); } reader.readAsDataURL(ev.dataTransfer.files[0]) },false) } //简化 document.getElementById() 函数 function getDomById(id){ return document.getElementById(id); } //图片预览处理函数 function showPrevImg(_img_container,_img_src){ //添加预览图片到容器框 var _imgs = _img_container.getElementsByTagName('img'); //容器中没有则建立,有则修改 src 属性 if(!_imgs.lenght){ _imgs[0] = document.createElement('img'); _imgs[0].setAttribute('src',_img_src); _img_container.appendChild(_imgs[0]); }else{ _imgs[0].setAttribute('src',_img_src); } }
代码分析
addEventListener('dragover',function(ev){ ev.preventDefault(); },false)
这段代码重点在于 ev.preventDefault();
阻止默认行为,若是咱们不阻止其默认行为将会产生下面的后果
接下来要作的就是拖放结束展现图片预览效果
_img_container.addEventListener('drop',function(ev){ ev.preventDefault(); reader.onload = function(ev){ //获取图片的url var _img_src = ev.target.result; //添加预览图片到容器框 showPrevImg(_img_container,_img_src); } reader.readAsDataURL(ev.dataTransfer.files[0]) },false)
这里用到 event.dataTransfer 咱们补充一下,咱们先来看下他的定义
dataTransfer 拖曳数据传递对象,其提供了对于预约义的剪贴板格式的访问,以便在拖曳操做中使用
通俗来说就是,咱们在拖曳操做中可使用它来操做咱们拖曳的对象。好比拖图片,经过它能拿到咱们所拖曳的图片对象
最后,强迫症犯了,稍微写了点样式美化了一下完整代码以下
<!DOCTYPE html> <html> <head> <title>Cboyce-HTML5图片预览</title> <style type="text/css"> body{ font-family: '微软雅黑'; } /*主容器*/ .container{ width: 90%; margin-top: 20px; } /*每个图片预览项容器*/ .img-prev-item{ width: 200px; height: 200px; display: inline-block; border:1px solid #ccc; text-align: center; border-radius: 3px; } /*图片预览容器*/ .container .img-prev-container{ width: 200px; height: 156px; margin: 0 auto; border-bottom: 1px solid #ccc; vertical-align: middle; display: table-cell; padding: 2px; color: #838383; text-align: center } /*预览图片样式*/ .container .img-prev-container img{ width: 100%; height: auto; max-height: 100%; } /*label*/ .selfile{ background-color: #0095ff; color: white; padding: 6px 58px; border-radius: 5px; } /*工具条 div*/ .tool{ padding-top: 9px; } /*隐藏文件选择器*/ #fileSelecter{ display: none; } </style> </head> <body> <div class="container"> <div class="img-prev-item"> <div class="img-prev-container" id="img-perv-div"> 请选择图片或者<br />将图片拖拽至此 </div> <div class="tool"> <label for="fileSelecter" class="selfile">请选择图片</label> <input type="file" value="请选择图片" id="fileSelecter" /> </div> </div> </div> <script type="text/javascript"> window.onload = function(){ //预览图的容器 var _img_container = getDomById('img-perv-div') //建立reader对象 var reader = new FileReader(); //触发 change 事件 getDomById('fileSelecter').onchange = function(event){ //获取文件对象 var file = event.target.files[0]; //读取完成后触发 reader.onload = function(ev){ //获取图片的url var _img_src = ev.target.result; //添加预览图片到容器框 showPrevImg(_img_container,_img_src); } //获取到数据的url 图片将转成 base64 格式 reader.readAsDataURL(file); } //添加拖放支持 _img_container.addEventListener('dragover',function(ev){ //ev.stopPropagation(); ev.preventDefault();//阻止默认事件。好比说Chrome是直接将图片用浏览器打开 console.log('dragover') },false) // _img_container.addEventListener('dragend',function(ev){ // ev.stopPropagation(); // ev.preventDefault(); // console.log('dragend') // },false) _img_container.addEventListener('drop',function(ev){ //ev.stopPropagation(); ev.preventDefault(); console.log('drop') //console.log(ev.dataTransfer.files[0]) reader.onload = function(ev){ //获取图片的url var _img_src = ev.target.result; //添加预览图片到容器框 showPrevImg(_img_container,_img_src); } reader.readAsDataURL(ev.dataTransfer.files[0]) },false) } //简化 document.getElementById() 函数 function getDomById(id){ return document.getElementById(id); } function showPrevImg(_img_container,_img_src){ _img_container.innerHTML=""; //添加预览图片到容器框 var _imgs = _img_container.getElementsByTagName('img'); //容器中没有则建立,有则修改 src 属性 if(!_imgs.lenght){ _imgs[0] = document.createElement('img'); _imgs[0].setAttribute('src',_img_src); _img_container.appendChild(_imgs[0]); }else{ _imgs[0].setAttribute('src',_img_src); } } //接下来要作的就是拖放结束展现图片预览效果 </script> </body> </html>
运行效果以下
基本上实现以及代码的原理也就解释到这了。其实前端作的图片预览功能大多数需求是用来上传到服务器的。不得不提到的是这里的拖拽预览虽然看起来体验不错,可是要将该文件上传就得作一些特殊处理。这个我就留到后面的博客再讲了,有问题的朋友能够直接留言。
限于笔者技术,文章观点不免有不当之处,但愿发现问题的朋友帮忙指正,笔者将会及时更新。也请转载的朋友注明文章出处并附上原文连接,以便读者能及时获取到文章更新后的内容,以避免误导读者。笔者力求避免写些晦涩难懂的文章(虽然也有人说这样显得高逼格,专业),尽可能使用简单的用词和例子来帮助理解。若是表达上有好的建议的话也但愿朋友们在评论处指出。
本文为做者原创,转载请注明出处! Cboyce