前言

基于ajax的异步模式的上传控件,基本功能如下:

拖拽上传(利用HTML5新增特定 拖拽事件 以及 event的dataTransfer属性)

单文件/多文件切换(利用php实现单/多文件上传)

上传进度实时显示(onprogress 以及其它属性)

拖拽上传的原理

拖拽事件

以前拖拽上传怎么完成的我不是很清楚,但是有了HTML5的拖拽事件之后特别方便。

简单介绍一下,这个拖拽事件有一整套,drog,dragstart,enter,over,drogend,drop等等

ondrag 元素被拖动时运行的脚本。

ondragend 在拖动操作末端运行的脚本。

ondragenter 当元素元素已被拖动到有效拖放区域时运行的脚本。

ondragleave 当元素离开有效拖放目标时运行的脚本。

ondragover 当元素在有效拖放目标上正在被拖动时运行的脚本。

ondragstart 在拖动操作开端运行的脚本。

ondrop 当被拖元素正在被拖放时运行的脚本。

我们主要用到的就是ondragover,ondragleave,ondrop

progress标签

progress是HTML5新增标签,通常用来显示任务的完成进度,主要属性有max,value,分别表示任务最大值,任务的当前完成值。

同时在生成的XHR对象中有一个upload.onprogress事件,可以对上传进度进行监视,可以通过该事件控制progress,实现上传预览。

dataTransfer属性

dataTransfer 是HTML5对event新增属性,且是完成拖拽上传的关键,通过该属性可以得到上传文件的所有信息

将它使用console打印在谷歌的debug上,如下图:

dataTransfer

拖拽上传主要用到它的files属性,其他属性就不多做详细介绍了。其中的files对象中的属性如下

files

其实相当于一个数组,拥有length属性,使能够一次拖拽多个文件,file[0]中将文件的创建时间,文件名,大小,类型等等都详细的列出来了。

FormData介绍

FormData也是上传文件的关键,创建的方式有多种

1、不传递任何参数 利用append加入参数

var fd = new FormData();

fd.append('name','content');

2、传递表单元素

var fd = new FormData(oForm);

相当与它创建了一个表单元素,可以将我们想传送到后台的数据添加进去。可以利用这个特性简化ajax的第三步拼接主体信息,直接使用FormData对象创建的第二种方法,就能够完成主体信息的拼接,而且不用再发送信息时对主体信息进行编码。

准备工作

具体网页布局如下:

布局

将文件放入虚线以内文件上传,且上传进度同步显示在网页上

由于其中获取的DOM元素较多,模仿jquery,我将dom获取放到一个函数中,较为方便。

function $(dom) {

var str = dom.charAt(0);

var ele = null;

switch( str ) {

// 获取class元素

case '.' :

ele = document.getElementsByClassName(dom.substring(1))||null;

break;

// 获取id元素

case '#' :

ele = document.getElementById(dom.substring(1)) || null;

break;

default :

if(document.getElementsByTagName(dom)) {

// 获取标签

ele = document.getElementsByTagName(dom);

} else if(document.getElementsByName(dom)) {

// 获取表单中的name元素

ele = document.getElementsByName(dom);

} else {

ele = null;

}

}

return ele;

}

且建立一个生成随机字符的函数,主要用在上传预览中生成随机的id号

// 随机字符串生成

function randomStr() {

var tmp = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';

var str = '';

for (var i = 0; i < 5; i++) {

str += tmp.charAt(Math.floor(Math.random()*tmp.length));

}

return str;

}

准备工作完成后开始正式编写上传控件

上传控件的编写

假设上传区域div的class元素名叫media

// 在目标区域拖拽

$('.media')[0].ondragover = function(ev) {

var oEvent = ev || window.event;

$('h3')[0].innerHTML = '松开鼠标后开始上传';

// 注意禁止浏览器默认事件

oEvent.preventDefault();

}

// 离开目标区域

$('.media')[0].ondragleave = function(ev) {

var oEvent = ev || window.event;

$('h3')[0].innerHTML = '拖拉文件到虚线框内上传';

// 注意禁止浏览器默认事件

oEvent.preventDefault();

}

// 目标文件落在目标区域

$('.media')[0].ondrop = function(ev) {

var oEvent = ev || window.event;

// 获取预览区域 生成预览

var oPreview = document.createElement('div');

var oProgress = document.createElement('progress');

oProgress.setAttribute('max',100);

oProgress.setAttribute('value',0);

// 生成不同的id 方便上传进度实时预览

var rstr = randomStr();

oPreview.setAttribute('class' , 'madia_upload_preview');

oPreview.setAttribute('id' , 'madia_upload_preview_' + rstr);

oPreview.appendChild(oProgress);

$('.media_upload').appendChild(oPreview);

// 获取form对象

var oForm = $('form')[0];

// 获取文件对象

var oFile = oEvent.dataTransfer;

/*

Ajax上传 下面介绍

*/

// 注意禁止浏览器默认事件

oEvent.preventDefault();

}

上述代码中在拖拽文件松开鼠标时,先生成出一个预览框体。如下图所示:

上传预览

且上述代码并没有加入ajax上传,接下来就来解决ajax的问题。

Ajax的封装

Ajax的功能简直强大了,你随便点开一个网页基本都有ajax的存在。当然这里不封装那么多功能,甚至对IE的兼容都不做,因为IE7以下不支持dataTransfer,所以没必要为其做兼容。

/** 参数介绍 使用方式 异步模式

* @param : method POST / GET 必须

* @param : path php文件路径 必须

* @param : fobj fileAPi以及form对象 必须格式是json格式{iFile:'',iForm:''}

* @param : func 回掉函数 可省略 请求php成功后执行的函数

*/

createAjax(method , path , fobj , func) {

// 生成一个标准xhr对象

var xhr = new XMLHttpRequest();

// 打开与php文件的连接

xhr.open(method , path , true);

// HTML5 file api 读取文件流

var far = fobj.iFile.files[0];

// 生成FrormData对象 FrormData也是HTML5新增对象 详情见上文

var fd = new FormData(fobj.iForm);

// 把文件流添加到文件流中

fd.append('file',far);

// 发送主体信息

xhr.send(fd);

// 等待响应信息

xhr.onreadystatechange = function() {

if(xhr.readyState == 4) {

if(func) {

func(xhr);

}

}

}

// 监听 上传进度

xhr.upload.onprogress = function(ev) {

var oEvent = ev || window.event;

if(oEvent.lengthComputable) {

// loaded是已上传文件大小 total是总文件大小

var par = 100 * oEvent.loaded / oEvent.total;

var oProgress = document.getElementsByTagName('progress')[0];

oProgress.value = par;

}

}

}

如上,对Ajax上传功能的封装就完成了,你不仅可以用它来连接php文件,还可以连接jsp,asp.net文件。当然你也可以在其中添加普通传送表单功能,你还可以添加大文件切割上传功能等等。

基本上利用ajax就这几步

生成xhr对象;

打开与后台文件的连接;

拼接主体信息

发送信息

监听响应信息

对上传进度的监听

首先观察这个事件的event对象

event

上图即为event对象的打印结果,total就是上次文件的总大小,loaded就是表示已上传的大小,两者相除即为上传的进度了。

那么为什么使用lengthComputable来进行判断是否显示进度呢?

因为在进行某些场景如大文件切割上传时是读取不到文件的上传大小的或者读取时不准确的,此时进行长度可读取判断是有必要的。

拖拽控件与Ajax封装完成接下来就要完成后台数据的处理了

文件上传类的封装

为了方便,这里直接封装一个文件上传类,以后可以直接使用。

class Uptool {

protected static $_ext = "jpg,jpeg,gif,png,bmp"; // 允许上传的文件类

protected static $Err = array( // 错误信息

0 => '正常',

1 => '文件超过系统最大限制',

2 => '文件大小超出上传最大限制',

3 => '文件只有部分被上传',

4 => '没有文件被上传',

6 => '找不到临时文件夹',

7 => '文件写入失败',

8 => '不允许的文件类型',

9 => '不得上传超过1M的文件',

10 => '创建目录失败'

);

public $Errnum = 0; // 错误信号

protected $_path = 'upload';

protected $data = array(); //

protected $maxsize = 1; // 最大上传文件 1M

/**

- 函数名:getFile

- 参 数:无

- 返回值:数组

- 功 能:获取$_FILES中的数据,赋给数组

*/

protected function getFile() {

foreach($_FILES as $key => $value) {

$this->data = $value;

}

return $this->data;

}

/**

- 函数名 : is_ext

- @param : $tmp array 一个由文件名及文件后缀组成的数组

- @return : array

- 功 能 : 是否符合规定的文件类型

*/

protected function is_ext($tmp) {

$ext = end($tmp);

// 如果不符合允许的类型

if(!in_array(strtolower($ext) , explode(',' , strtolower(self::$_ext)))) {

$this->Errnum = 8; // 赋值错误数字

return false;

}

return true;

}

/**

- 函数名 : mk_dir

- @param : $path string 创建的文件目录路径

- @return: string

- 功 能 : 创建目录

*/

protected function mk_dir($path) {

if(!is_dir($path)) {

return mkdir($path , 0777 , true);

} else {

return $path;

}

}

/**

- 函数名 :setPath

- @param :string $path 要设置的路径

- @return :bool

- 功 能 :修改上传文件的路径

*/

public function setPath($path) {

if(!is_string($path)) {

return false;

} else {

$this->_path = $path;

return true;

}

}

/**

- 函数名 :UpFile

- @param :int $key 默认值0 多文件上传文件序号

- @return :bool

- 功 能:上传文件

*/

public function upFile($key = 0) {

// 获取上传的文件信息

$this->data = $this->getFile();

// 判断是否为多文件上传 上传信息是数组使用键值,否则不使用

$size = is_array($this->data['size'])?$this->data['size'][$key]:$this->data['size'];

$tmp = is_array($this->data['name'])?explode('.',$this->data['name'][$key]):explode('.',$this->data['name']);

$tmp_name = is_array($this->data['tmp_name'])?$this->data['tmp_name'][$key]:$this->data['tmp_name'];

// 判断文件类型 不符合直接结束

if(!$this->is_ext($tmp)) {

return false;

}

// 判断文件大小是否符合

if( $size > $this->maxsize * 1024 * 1024) {

$this->Errnum = 9;

return false;

}

// 到本行说明文件符合规定

// 使用用户名创建目录

$user = $_SESSION['user_name'];

$fpath = '/data/' . $this->_path . '/' . $user . '/' . date('Y-m-H' , time());

$path = ROOT . $fpath;

// 创建目录 失败直接结束

$path = $this->mk_dir($path);

if(!$path) {

$this->Errnum = 10;

return false;

}

// 创建随机文件名

$pname = '/'. mt_rand(100000,999999) . '.' . end($tmp);

$path .= $pname;

$fpath .= $pname;

// 转移文件

if(!move_uploaded_file($tmp_name , $path)) {

$this->Errnum = $this->data['error'];

return false;

}

return $fpath;

}

/**

- 多文件上传

- @param 无

- @return bool(false)

*/

public function moreUpFile() {

// 获取文件信息

$this->data = $this->getFile();

// 循环上传文件

foreach($this->data['error'] as $key => $error) {

if($error === 0) {

$this->upFile($key);

} else {

$this->Errnum = $error;

return false;

}

}

}

/**

- 函数名 :getErr

- @param :$num

- @return :数组

- 功 能 :打印错误

*/

public function getErr($num) {

return self::$Err[$num];

}

}

上传功能实现

前台数据发送

已经封装好了AJAX应用后,就可以利用其发送数据到后台了。

// 承接上面JS代码

createAjax('post' , './upload.php' , true , {

'iFile': oFile,

'iForm': oForm

} , function(xhr) {

var bool = xhr.responseText.split('|')[0];

var oInfo = xhr.responseText.split('|')[1];

var oName = document.createElement('div');

var oSpan = document.createElement('span');

var oPre = $('#madia_upload_preview_' + rstr)[0]; // 获取上面建立的随机id

// 如果bool == true 说明上传成功

if(bool) {

var tmp = JSON.parse(oInfo); // 将后台返回的数据转换成json格式

// 建立图片预览

var oImg = document.createElement('img');

oImg.setAttribute('src' , '..' + tmp[0].path);

oName.setAttribute('class' , 'image_title');

oSpan.innerHTML = tmp[0].path.split('/')[tmp[0].path.split('/').length-1]; // 截取文件名

oName.appendChild(oSpan);

oPre.appendChild(oImg);

oPre.appendChild(oName);

} else {

// 否则 上传失败 显示失败信息

oSpan.innerHTML = oInfo;

oName.appendChild(oSpan);

oPre.appendChild(oName);

}

// 消除progress 否则每次上传进度都只会在第一个文件中显示

var oProgress = $('progress')[0];

oPre.removeChild(oProgress);

}) ;

将上述代码添加到前面的js代码中,就组成了一个完整的拖拽上传控件了。当拖拽文件到指定区域,松开鼠标就会进行上传。

当然还需要后台upload.php文件的合作。

后台数据处理

if(isset($_POST['hid']) && $_POST['hid'] == 'upload' ) {

// 文件上传路径判断 无的话 上传到默认目录

$path = isset($_POST['path'])?$_POST['path']:'';

$up = new Uptool();

// 设置上传目录

if($path) {

$up->setPath($path);

}

$path = $up->UpFile();

if($path) {

$size = getimagesize(ROOT . $path);

$info = '[{"path":"' . $path . '","width":' . $size[0] . ',"height":' . $size[1] . '}]';

echo 'true|' . $info;

} else {

echo 'false|' . $up->getErr($up->Errnum);

exit();

}

}

这样一个单文件上传的功能已经完成,如果要多文件上传只要将upload.php文件中的UpFile方法修改成moreUpFile即可。

到这里一个完整的基于HTML5与ajax完成拖拽上传控件就完成了,在下才疏学浅,如有错误,欢迎指正。

html ajax打包成app,利用HTML5与ajax完成拖拽上传文件相关推荐

  1. 使用jQuery开发一个基于HTML5的漂亮图片拖拽上传web应用

    昨天我们介绍了一款HTML5文件上传的jQuery插件:jQuery HTML5 uploader,今天我们将开发一个简单的叫upload center的图片上传程序,允许用户使用拖拽方式来上传电脑上 ...

  2. html5 拖拽上传文件时,屏蔽浏览器默认打开文件

    参考: https://www.cnblogs.com/kingsm/p/9849339.html 转载于:https://www.cnblogs.com/cwxwdm/p/10605529.html

  3. [开源应用]利用HTTPHandler+resumableJs+HTML5实现拖拽上传[大]文件

    前言: 大文件传输一直是技术上的一大难点.文件过大时,一些性提交所有的内容进内存是不现实的.大文件带来问题还有是否支持断点传输和多文件同时传输. 本文以resumableJs为例,介绍了如何在ASP. ...

  4. 利用HTML5新特性实现拖拽交换表格单元格元素

    利用HTML5新特性实现拖拽交换表格单元格元素 HTML5新特性:拖放 拖放 拖放(Drag 和 Drop)是很常见的特性.它指的是您抓取某物并拖入不同的位置. 拖放是 HTML5 标准的组成部分:任 ...

  5. Nodejs express、html5实现拖拽上传(转载)

    一.前言 文件上传是一 个比较常见的功能,传统的选择方式的上传比较麻烦,需要先点击上传按钮,然后再找到文件的路径,然后上传.给用户体验带来很大问题.html5开始支持拖 拽上传的需要的api.node ...

  6. html5之多文件拖拽上传预览

    最近对于html5预览功能很是感兴趣,特地拿出来研究一小下,并以一个小项目举例讲解. h5中的input有个type=file 就是文件上传控件,有个属性multiple就是h5新增的支持多选上传文件 ...

  7. html5 上传超大文件,HTML5教程 如何拖拽上传大文件

    本篇教程探讨了HTML5教程 如何拖拽上传大文件,希望阅读本篇文章以后大家有所收获,帮助大家HTML5+CSS3从入门到精通 . < 前言: 大文件传输一直是技术上的一大难点.文件过大时,一些性 ...

  8. 拖拽上传技术-----html5[转载]

    原网址:http://blog.163.com/mongying_net/blog/static/35112712012345352226/ 拖拽上传应用主要使用了以下HTML5技术: Drag&am ...

  9. html5带拖拽上传的图片gallary

    改的别人的程序,不能说原创吧,算半个原创 <!DOCTYPE html> <!-- saved from url=(0066)http://enjoyhtml5.com/hackat ...

最新文章

  1. 转:Tkinter教程之Text(2)篇
  2. ASP.NET 中的表单身份验证(Forms Authentication)
  3. 红帽子linux安装ftp,Linux 安装 vsftpd ftp软件包
  4. 光流(五)--HS光流及稠密光流
  5. linux打开cap文件,cap/pcap类文件无法用wireshark打开
  6. golang 读写 xlsx 文件
  7. 思科交换机与路由器常用基础配置
  8. openpyxl 数字格式处理
  9. Qt 及QT VS Tools插件官方下载及安装
  10. Delphi使用CEF4Delphi制作Chromium谷歌内核浏览器
  11. HTML之基础标签_思维导图版
  12. java-php-python-ssm-心灵治愈服务平台-计算机毕业设计
  13. python重新执行条件_Python 基础(二)
  14. 【新书推荐】【2011.06】唐缺:不一样的推理密谋全集(套装共7册)
  15. 聚焦低代码SaaS云服务,让企业轻松办公!
  16. pandas的DataFrame数据画图matplotlab曲线如何改变时间刻度【间隔时间】并格式化日期显示总结
  17. 笔记本Win7系统 设置WIFI热点共享无线网络
  18. oracle第五章多表连接习题答案(理解+剖析)
  19. 原来微信还有这三个实用小技巧!简直太方便了
  20. SQL学习笔记(三): 视图与一些复杂查询(虽复杂但常用)

热门文章

  1. android获取cookie
  2. Python之numpy库——numpy.exp()函数
  3. 面试|你了解RTTI吗
  4. 从BSV下架风波, 揭秘构造区块链分叉的测试方案 | 技术头条
  5. Python内存模型
  6. 如果有一天你失业还不起房贷了,该怎么办?
  7. 微信开发者工具登录后无法预览和真机调试?无语解决
  8. Hook(钩子)技术的含义和工作原理
  9. 弘辽科技:直通车选几个词比较好?关键词怎么去选择?
  10. c语言罗,c语言俄罗块游戏程序设计报告.doc