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 相关文章推荐
js中cookie的使用详细分析
May 28 Javascript
JavaScript 语言的递归编程
May 18 Javascript
intro.js 页面引导简单用法 分享
Aug 06 Javascript
jquery统计复选框选中示例
Nov 05 Javascript
JavaScript设计模式之工厂方法模式介绍
Dec 28 Javascript
JavaScript简单实现弹出拖拽窗口(一)
Jun 17 Javascript
详解微信小程序开发之城市选择器 城市切换
Jan 17 Javascript
Vue.js进阶知识点总结
Apr 01 Javascript
vue-cli2与vue-cli3在一台电脑共存的实现方法
Sep 25 Javascript
javascript设计模式 ? 代理模式原理与用法实例分析
Apr 16 Javascript
three.js欧拉角和四元数的使用方法
Jul 26 Javascript
js不常见操作运算符总结
Nov 20 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
2020显卡排行榜天梯图 显卡天梯图2020年3月最新版
2020/04/02 数码科技
虚拟主机中对PHP的特殊设置
2006/10/09 PHP
UTF8编码内的繁简转换的PHP类
2009/07/09 PHP
PHP多个版本的分析解释
2011/07/21 PHP
关于PHPDocument 代码注释规范的总结
2013/06/25 PHP
centos+php+coreseek+sphinx+mysql之一coreseek安装篇
2016/10/25 PHP
php数据库操作model类(使用__call方法)
2016/11/16 PHP
初学Jquery插件制作 在SageCRM的查询屏幕隐藏部分行的功能
2011/12/26 Javascript
javascript 三种方法实现获得和设置以及移除元素属性
2013/03/20 Javascript
jquery 文本上下无缝滚动,鼠标放上去就停止 小例子
2013/06/05 Javascript
3分钟写出来的Jquery版checkbox全选反选功能
2013/10/23 Javascript
JavaScript实现的内存数据库LokiJS介绍和入门实例
2014/11/17 Javascript
javascript判断并获取注册表中可信任站点的方法
2015/06/01 Javascript
javascript 动态样式添加的简单实现
2016/10/11 Javascript
mui上拉加载更多下拉刷新数据的封装过程
2017/11/03 Javascript
jquery获取transform里的值实现方法
2017/12/12 jQuery
js中的闭包学习心得
2018/02/06 Javascript
Layui Table js 模拟选中checkbox的例子
2019/09/03 Javascript
基于vue+echarts 数据可视化大屏展示的方法示例
2020/03/09 Javascript
vue数据更新UI不刷新显示的解决办法
2020/08/06 Javascript
基于Vant UI框架实现时间段选择器
2020/12/24 Javascript
[07:54]DOTA2-DPC中国联赛 正赛 iG vs VG 选手采访
2021/03/11 DOTA
Python的垃圾回收机制深入分析
2014/07/16 Python
Python编程中归并排序算法的实现步骤详解
2016/05/04 Python
Matplotlib 生成不同大小的subplots实例
2018/05/25 Python
itchat-python搭建微信机器人(附示例)
2019/06/11 Python
pytorch torchvision.ImageFolder的用法介绍
2020/02/20 Python
CSS实现圆形放大镜狙击镜效果 只有圆圈里的放大
2012/12/10 HTML / CSS
HTML5 Canvas 起步(2) - 路径
2009/05/12 HTML / CSS
飞利浦西班牙官方网站:Philips西班牙
2020/02/17 全球购物
计算机专业毕业生自荐信范文
2014/03/06 职场文书
计算机毕业大学生求职信
2014/06/26 职场文书
2014年中秋寄语
2014/08/11 职场文书
鸟的天堂导游词
2015/01/31 职场文书
写好求职信的技巧解密
2019/05/14 职场文书
深入理解go缓存库freecache的使用
2022/02/15 Golang