ajax文件上传

文章首发于qdgithub.com阅读体验更佳

iframe模拟Ajax文件上传效果

分析:

1:捕捉表单提交的动作

2:创建一个iframe

3:把表单的 target修改 指向 该iframe

4:去掉这个iframe

<div id="progress">div>
<form action="up.php" method="post" enctype="multipart/form-data" onsubmit="return ajaxup();">
	<input type="file" name="pic">
	<input type="submit" value="提交">
form>
<script>
	function ajaxup() {
		var ifname = 'up' + Math.random();
		$('').appendTo($('body'));
		$('form:first').attr('target', ifname);
		$('#progress').html('');
	}
script>
sleep(3);

if(empty($_FILES)) {
    exit('no file');
}

$msg = $_FILES['pic']['error']==0 ? 'succ' : 'fail';

echo "";

formData发送数据

formData "表单数据"对象,这是在html5中新增的一个Api。
他能以表单对象做参数,自动的把表单的数据打包.
当ajax发送数据时,发送些formData,达到发送表单内各数据项的目的。

// 02-testpost.php
print_r($_POST);
<form id="tform">
	用户名:<input type="text" name="username"><br>
	年 龄:<input type="text" name="age"><br>
	email:<input type="text" name="email"><br>
	性 别:<input type="text" name="gender"><br>
	<input type="button" value="ajax发送" onclick="send();">
form>
<div id="debug">div>
<script type="text/javascript">
	function send() {
		var fm = document.getElementById('tform');
		var fd = new FormData(fm);

		var xhr = new XMLHttpRequest();
		xhr.open('POST', '02-testpost.php', true);

		xhr.onreadystatechange = function () {
			if (this.readyState == 4) {
				document.getElementById('debug').innerHTML = this.responseText;
			}
		}

		xhr.send(fd);

		// 看下面这个例子,说明formData对象既可以从表单生成数据,也可以手动的append
		var fd2 = new FormData();
		fd2.append('username', 'zhangsanm');
		fd2.append('age', 23);
		xhr.send(fd2);
	}
script>

把二进制对象转换成浏览器显示的资源

<input type="file" name="pic" onchange="selfile();">
<div id="debug">div>
<script type="text/javascript">
	function selfile() {
		var pic = document.getElementsByTagName('input')[0].files[0];
		console.log(pic);
		var debug = document.getElementById('debug');
		var content = '';
		content += '文件名称:' + pic.name + '
'
; content += '文件大小' + pic.size + '
'
; debug.innerHTML = content; var tmpimg = document.createElement('img'); tmpimg.style.width = '300px'; tmpimg.src = window.URL.createObjectURL(pic); // 把二进制对象直接读成浏览器显示的资源 document.getElementsByTagName('body')[0].appendChild(tmpimg); }
script>

pic变量打印值,如下图所示:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-F9PqWeKZ-1576402860323)(/Uploads/2019-12-12/5df25ea50294e.png)]

通过form表单把图片发送到服务器

<input type="file" name="pic" onchange="selfile();">
<div id="debug">div>
<script type="text/javascript">
	function selfile() {
		var fd = new FormData();
		var pic = document.getElementsByTagName('input')[0].files[0];
		// 把文件内容追加到表单数据里
		fd.append('pic', pic);

		var xhr = new XMLHttpRequest();
		xhr.open('POST', '04-upfile.php', true);

		xhr.onreadystatechange = function () {
			if (this.readyState == 4) {
				document.getElementById('debug').innerHTML = this.responseText;
			}
		}

		xhr.send(fd);
	}
script>

把图片移动到上传目录

if(empty($_FILES)) {
    exit('no file');
}

if($_FILES['pic']['error'] != 0) {
    exit('fail');
}

move_uploaded_file($_FILES['pic']['tmp_name'],'upload/'.$_FILES['pic']['name']);

echo 'ok';

上传显示进度条

进度条需要2个最基础的信息— 总大小,已上传大小

解决: 在html5,有一个"上传过程"的事件–onprogress事件中可以读到这2个信息

具体思路: 在上传过程中,不断的触发函数,函数读取已上传/总大小,更新页面的进度条。

<style type="text/css">
	#progress {
	  width: 500px;
	  height: 30px;
	  border: 1px solid green;
	}

	#bar {
	  width: 0%;
	  height: 100%;
	  background: green;
	}
style>
<div id="progress"><div id="bar">div>div>
<input type="file" onchange="selfile();">
<script type="text/javascript">
	function selfile() {
	  var fd = new FormData();
	  var video = document.getElementsByTagName('input')[0].files[0];
	  fd.append('video', video);

	  var xhr = new XMLHttpRequest();
	  xhr.open('POST', 'upload.php', true);


	  // 利用XHR2的新标准,为上传过程,写一个监听函数
	  xhr.upload.onprogress = function (ev) {
		console.log(ev);
		if (ev.lengthComputable) {
		  var percent = 100 * ev.loaded / ev.total;
		  document.getElementById('bar').style.width = percent + '%';
		  document.getElementById('bar').innerHTML = parseInt(percent) + '%';
		}
	  }

	  xhr.send(fd);
	}
script>

// upload.php
header('Access-Control-Allow-Origin: *');
// 如果接收不到文件
// 请确定 post_max_size upload_max_filesize 的大小(php.ini中)
$upfile = $_FILES['video'];

function upload_file($files, $path = "./upload", $imagesExt = ['jpg', 'png', 'jpeg', 'gif','avi', 'mp4','wmv'])
{
    // 判断错误号
    if (@$files['error'] == 00) {
        // 判断文件类型
        $ext = strtolower(pathinfo(@$files['name'], PATHINFO_EXTENSION));
        if (!in_array($ext, $imagesExt)) {
            return "非法文件类型";
        }

        // 判断是否存在上传到的目录
        if (!is_dir($path)) {
            mkdir($path, 0777, true);
        }

        // 生成唯一的文件名
        $fileName = md5(uniqid(microtime(true), true)) . '.' . $ext;

        // 将文件名拼接到指定的目录下
        $destName = $path . "/" . $fileName;

        // 进行文件移动
        if (!move_uploaded_file($files['tmp_name'], $destName)) {
            return "文件上传失败!";
        }
        return "文件上传成功!";
    } else {
        // 根据错误号返回提示信息
        switch (@$files['error']) {
            case 1:
                echo "上传的文件超过了 php.ini 中 upload_max_filesize 选项限制的值";
                break;
            case 2:
                echo "上传文件的大小超过了 HTML 表单中 MAX_FILE_SIZE 选项指定的值";
                break;
            case 3:
                echo "文件只有部分被上传";
                break;
            case 4:
                echo "没有文件被上传";
                break;
            case 6:
            case 7:
                echo "系统错误";
                break;
        }
    }

}

echo upload_file($upfile);

HTML5大文件切割上传

File 继承自 Blob,Blob有slice方法,可以截取二进制对象的一部分。

思路:

1.截取10M,上传

2.判断文件有没有上传完毕。没有,继续重复步骤1、2

<style type="text/css">
	#progress {
		width: 500px;
		height: 30px;
		border: 1px solid green;
	}

	#bar {
		width: 0%;
		height: 100%;
		background: green;
	}
style>
<div id="progress">
	<div id="bar">div>
div>
<input type="file" name="mov" onchange="fire();">
<script type="text/javascript">
var xhr = new XMLHttpRequest(),clock = null;

function fire() {
    clock = window.setInterval(sendfile,1000);
}

// 闭包计数器
var sendfile = (function() {

    const LENGTH = 10 * 1024 * 1024; //每次切10M 
    var sta = 0;
    var end = sta + LENGTH;
    var sending = false; // 标志正在上传中
    
    var blob = null;
    var fd = null;

    // 百分比 
    var percent = 0;


    return (function () {       
        if(sending == true) {
            return;
        }
        
        var mov = document.getElementsByName('mov')[0].files[0];
        // 如果sta>mov.size,就结束了
        if(sta > mov.size) {
            clearInterval(clock);
            return;
        }
        
        blob = mov.slice(sta,end);
        
        fd = new FormData();
        fd.append('part',blob);

        up(fd);

        sta = end;
        end = sta + LENGTH;
        sending = false; // 上传完了


        percent = 100 * end / mov.size;
        if(percent > 100) {
            percent = 100;
        }
        document.getElementById('bar').style.width = percent + '%';
    });

})();

function up(fd) {
    xhr.open('POST','06-sliceup.php',false);
    xhr.send(fd);
}
script>
// 06-sliceup.php
// 接收文件并合并
if(!file_exists('./upload/hhr.mov')) {
    move_uploaded_file($_FILES['part']['tmp_name'],'./upload/hhr.mov');
} else {
    file_put_contents('./upload/hhr.mov',file_get_contents($_FILES['part']['tmp_name']),FILE_APPEND);
}

echo 'ok';

你可能感兴趣的:(【JavaScript】)