js实现图片上传预览原理分析


Posted in Javascript onJuly 13, 2017

目前网上有很多支持图片上传时进行预览的插件,功能完备,界面优雅,使用起来也很方便。一直以来也就只是用用,没有想过这些插件背后的实现原理。趁着今天有点时间,也来学习学习。

追根溯源

设想

一开始,按照我的思路,预览可能是这么来实现的。本地选中一张图片,嵌入html的同时会显示图片的本地的绝对路径,然后通过js简单的进行设置,应该就可以实现预览效果了。

但是实际上,目前只有低版本的IE浏览器才能实现这么个效果。究其原因是浏览器厂商为了进一步强化安全,限制了file标签直接读取本地路径的能力,在HTML5下只有通过FileReader的API来实现这一需求了。
比如对于CSDN写博客的时候上传一张图片,得到的只会是一个fakepath。有图为证:

js实现图片上传预览原理分析

原理

FileReader就是html5为我们提供的读取文件的api。它的作用就是把文本流按指定格式读取到缓存,以供js调用。

FileReader有四种读取文件的方式:
 1.readAsBinaryString读取为二进制码

 2.readAsDataURL读取为 DataURL

 3.readAsText读取为文本

 4.readAsArrayBuffer

根据本次实现的目标,使用第二种方式即可。img标签的src就是这个图片的编码后的DataURL。如图所示:

js实现图片上传预览原理分析

DataURL浅析

DataURL 说来可是有很多内容要研究的,但是这次用的比较浅显,就把基础的了解下就行了。

格式

DataURL有其固定的格式,如下:

data:[文件格式];base64,[文本流base64编码]。

举个例子:
 •jpg格式: data:image/jpeg;base64,/9j/4...
 •png格式: data:image/png;base64,iVBORw...
 •gif格式: data:image/gif;base64,R0lGOD... 

•png格式的图片编码信息 

js实现图片上传预览原理分析

预览实现

好了,弄明白了这些原理性的东西,就可以着手进行实现了。

HTML

<form action="#" method="POST">
 <legend>
 图片上传
 </legend>
 <fieldset>
 <input type="file" name="pic1" id="pic1" onchange="preview(this)" multiple="multiple"
 accept="image/x-png, image/jpg, image/jpeg, image/gif">
 <br><br>
 </fieldset>
 <input type="button" value="上传">
</form>
<div id="container">


</div>

在代码中使用了Html5的一些新特性。用来过滤待上传的图片格式。

JavaScript控制

接下来就是预览功能的实现了。目标就是将图片转换成DataURL,然后对预览区进行子元素的添加操作。

<script>
 var msg = "您可以上传png, jpg, 或者gif格式的图片";
 var filter = {
 "jpeg": "/9j/4",
 "gif": "R0lGOD",
 "png": "iVBORw"
 };
 function preview(file) {
 var container = document.getElementById("container");
 container.innerHTML = "";
 if (window.FileReader) {
 for (var index=0, f; f = file.files[index]; index++) {

 var filereader = new FileReader();
 filereader.onload = function (event) {
 var srcpath = event.target.result;
 if (!validateImg(srcpath)) {
 console.log("H5"+msg);
 } else {
 showPreviewImage(srcpath);
 }
 };
 filereader.readAsDataURL(f);
 }
 } else {
 if (!/\.jpg$|\.png$|\.gif$/i.test(file.value)) {
 console.log("原生"+msg);
 } else {
 showPreviewImage(file.value);
 }
 }
 }

 function validateImg(data) {
 console.log(data);
 var pos = data.indexOf(",") + 1;
 for (var e in filter) {
 if (data.indexOf(filter[e]) === pos) {
 return e;
 }
 }
 return null;
 }

 function showPreviewImage(src) {
 console.log(src);


 var img = document.createElement('img');
 img.src = src;
 img.style = "width:64px;height:auto;"
 container.appendChild(img);
 }

</script>

预览效果

总的来说代码就算是完成了,接下来看下实现的效果。由于没有设置样式,所以看起来很简陋,有兴趣的自己用样式控制一下即可。

js实现图片上传预览原理分析

打包封装

简易封装

为了方便实用,特使用原生JavaScript封装了一个这样的组件。详细代码如下:

/**
 * Created by biao on 2017/7/10.
 * Description: A simple tool for previewing images for uploading.
 * Blog: http://blog.csdn.net/marksinoberg
 * GitHub: https://github.com/guoruibiao
 */

function ImgPrevirewer(config) {

 /**
 * The tag ID for upload images.
 */
 this.fileId = config.fileId;

 /**
 * tip for error message.
 * @type {string}
 */
 this.tip = config.tip;
 /**
 * The ID for the container which contains img tags.
 * @type {string}
 */
 this.containerId = config.containerId;
 /**
 * CSS style for previewing imgs.
 * @type {string}
 */
 this.imgStyle = config.imgStyle;

 /**
 * 过滤图片格式,可进行相对应的删减操作。
 * @type {{jpeg: string, gif: string, png: string}}
 */
 this.filter = {
 /**
 * jpg或者jpeg格式的图片。
 */
 "jpeg": "/9j/4",
 /**
 * gif格式的图片。
 */
 "gif": "R0lGOD",
 /**
 * PNG格式的图片。
 */
 "png": "iVBORw"
 };


 /**
 * 开始预览。自动调用原生JavaScript实现相关元素的定位以及渲染。
 */
 this.preview = function () {
 var file = document.getElementById(this.fileId);
 var container = document.getElementById(this.containerId);
 container.innerHTML = "";
 /**
 * 防止内部作用域覆盖问题。
 * @type {ImgPrevirewer}
 */
 var that = this;
 // HTML5 需要使用FileReader的相关API来读取本地数据。
 if (window.FileReader) {
 // 针对多个上传文件批量处理。
 for (var index = 0, f; f = file.files[index]; index++) {
 var filereader = new FileReader();
 filereader.onload = function (event) {
 var srcpath = event.target.result;
 if (!that.validateImg(srcpath)) {
 console.log(this.tip);
 } else {
 that.showPreviewImg(srcpath);
 }
 };
 filereader.readAsDataURL(f);
 }
 } else {
 // 低版本降级处理。
 if (!/\.jpg$|\.png$|\.gif$/i.test(file.value)) {
 console.log(this.tip);
 } else {
 that.showPreviewImg(file.value);
 }
 }
 }


 /**
 * 根据图片的base64编码格式查看图片是否符合要求。
 * @param data 编码后的图片数据。
 * @returns {*}
 */
 this.validateImg = function (data) {
 var pos = data.indexOf(",") + 1;
 for (var e in this.filter) {
 if (data.indexOf(this.filter[e]) === pos) {
 return e;
 }
 }
 return null;
 }

 /**
 * 开始实现对图片的预览,根据this.imgStyle进行相关渲染操作。
 * @param src
 */
 this.showPreviewImg = function (src) {
 var img = document.createElement('img');
 img.src = src;
 img.style = this.imgStyle;
 container.appendChild(img);
 }


}

使用方式

下面来一个简单的“模板式”使用技巧。

<!DOCTYPE html>
<html lang="en">
<head>
 <meta charset="UTF-8">
 <title>Test</title>
 <script src="img-previewer.js"></script>
</head>
<body>
<input type="file" id="file" multiple onchange="preview()">
<div id="container">

</div>

<script>

 function preview(){
 var config = {
 tip: "请上传格式为png, gif或者jpg的图片",
 fileId: "file",
 containerId: "container",
 imgStyle: "width:320px;height:auto;border-radius:64%;"
 }
 var previewer = new ImgPrevirewer(config);
 previewer.preview();
 }

</script>
</body>
</html>

测试

为了保证这个组件的稳定性,接下来来个简单的测试。

首先是在Chrome浏览器上,发现可以正常工作。

js实现图片上传预览原理分析

接下来是在Edge浏览器上的测试。(发现样式不兼容)

js实现图片上传预览原理分析

不出所料,IE系的浏览器样式都没能兼容。

js实现图片上传预览原理分析

最终发现,Chrome等WebKit内核的浏览器可以完美支持,对于微软系浏览器而言,功能可以满足,但是样式上不兼容,这点可以通过特定的浏览器头来实现,不再过多叙述。

总结

总的来说,关于图片上传时的预览功能,实用性还是很强的。对于一个网站可以算是一个加分项。当然了,该网站有一个设计感不错的美工或者前端,不像我做出的页面好难看(⊙?⊙)b。

大概就是这样咯,有需要的尽管拿去使用。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
讲两件事:1.this指针的用法小探. 2.ie的attachEvent和firefox的addEventListener在事件处理上的区别
Apr 12 Javascript
JS中处理与当前时间间隔的函数代码
May 23 Javascript
jQuery 网易相册鼠标移动显示隐藏效果实现代码
Mar 31 Javascript
JQuery事件e参数的方法preventDefault()取消默认行为
Sep 26 Javascript
JS过滤url参数特殊字符的实现方法
Dec 24 Javascript
Jquery实现简单的轮播效果(代码管用)
Mar 14 Javascript
jQuery.Callbacks()回调函数队列用法详解
Jun 14 Javascript
如何制作幻灯片(代码分享)
Jan 06 Javascript
jQuery实现优雅的弹窗效果(6)
Feb 08 Javascript
js实现多个标题吸顶效果
Jan 08 Javascript
基于JavaScript实现控制下拉列表
May 08 Javascript
React 高阶组件HOC用法归纳
Jun 13 Javascript
vue.js数据绑定的方法(单向、双向和一次性绑定)
Jul 13 #Javascript
Easyui Datagrid自定义按钮列(最后面的操作列)
Jul 13 #Javascript
AngularJS 实现点击按钮获取验证码功能实例代码
Jul 13 #Javascript
解决Vue页面固定滚动位置的处理办法
Jul 13 #Javascript
vue+ElementUI实现订单页动态添加产品数据效果实例代码
Jul 13 #Javascript
Angular如何引入第三方库的方法详解
Jul 13 #Javascript
详解如何构建Angular项目目录结构
Jul 13 #Javascript
You might like
PHP+MYSQL的文章管理系统(一)
2006/10/09 PHP
PHP 万年历实现代码
2012/10/18 PHP
preg_match_all使用心得分享
2014/01/31 PHP
PHP中strtr字符串替换用法详解
2014/11/26 PHP
PHP+jquery实时显示网站在线人数的方法
2015/01/04 PHP
PHP的HTTP客户端Guzzle简单使用方法分析
2019/10/30 PHP
Node.js生成HttpStatusCode辅助类发布到npm
2013/04/09 Javascript
目前流行的JavaScript库的介绍及对比
2013/09/29 Javascript
jQuery实现复选框全选/取消全选/反选及获得选择的值
2014/06/12 Javascript
jQuery中detach()方法用法实例
2014/12/25 Javascript
Javascript中的arguments与重载介绍
2015/03/15 Javascript
jQuery实现的给图片点赞+1动画效果(附在线演示及demo源码下载)
2015/12/31 Javascript
JavaScript随机打乱数组顺序之随机洗牌算法
2016/08/02 Javascript
给easyui datebox扩展一个清空的实例
2016/11/09 Javascript
JS时间控制实现动态效果的实例讲解
2017/07/31 Javascript
react 父子组件之间通讯props
2018/09/08 Javascript
js中关于Blob对象的介绍与使用
2019/11/29 Javascript
[03:26]《DAC最前线》之EG经理自述DOTA2经历
2015/02/02 DOTA
Python实现的数据结构与算法之双端队列详解
2015/04/22 Python
5种Python单例模式的实现方式
2016/01/14 Python
Python Dataframe 指定多列去重、求差集的方法
2018/07/10 Python
Django使用redis缓存服务器的实现代码示例
2019/04/28 Python
python打印9宫格、25宫格等奇数格 满足横竖斜相加和相等
2019/07/19 Python
python实现实时视频流播放代码实例
2020/01/11 Python
Django视图、传参和forms验证操作
2020/07/15 Python
html5 postMessage解决跨域、跨窗口消息传递方案
2016/12/20 HTML / CSS
abstract 可以和 virtual 一起使用吗?可以和 override 一起使用吗?
2012/10/15 面试题
一道Delphi上机题
2012/06/04 面试题
设计毕业生简历中的自我评价
2013/10/01 职场文书
大三预备党员入党思想汇报
2014/01/08 职场文书
推荐信格式范文
2014/05/09 职场文书
体育专业自荐书
2014/05/29 职场文书
党员先进事迹材料
2014/12/19 职场文书
学习焦裕禄先进事迹心得体会
2016/01/23 职场文书
Python趣味挑战之给幼儿园弟弟生成1000道算术题
2021/05/28 Python
vue整合百度地图显示指定地点信息
2022/04/06 Vue.js