前端文件上传

一丶前端文件上传方式

前端网页文件上传一般使用 来实现。
在 HTML 文档中: <input type="file" />标签每出现一次,一个 FileUpload 对象就会被创建。该标签包含一个文本输入字段,用来输入文件名,还有一个按钮,用来打开文件选择对话框以便图形化选择文件,该标签的 value属性保存了用户指定的文件的名称。
多选: 标签可以通过添加 multiple 属性来支持多选;如果选择了多个文件, 这个值表示第一个被选择的文件路径. JavaScript 可以通过 Input 的 FileList属性获取到其他的文件路径.
文件信息:可以通过 input.files 属性返回 — 返回值是一个 FileList 对象,这个对象是一个包含了许多 File 文件的列表,列表包含图片的name,type,size 等属性。
限制文件类型:你可以使用 input 的 accept 属性,accept 属性接受一个逗号分隔的 MIME 类型字符串。如: accept=“image/png, image/jpeg” or accept=".png, .jpg, .jpeg" — PNG/JPEG
选择文件:会触发input的onchange事件;
上传:上传文件前 使用FileReader对象读取指定file的文件,并将文件转换为二进制字符串, 并将xhr对象, overrideMimeType 属性设置为text/plain; charset=x-user-defined-binary, 最终后台接收到二进制后再做具体处理。

第一种:经典的form和input上传

设置form的aciton为后端页面,必填项:enctype=“multipart/form-data”,type=‘post’

<form action='uploadFile.php' enctype="multipart/form-data" type='post'>
  <input type='file'>
  <input type='hidden' name='userid'>  
  <input type='hidden' name='signature'>
  <button>提交</button>
</form>

使用input选择文件,设置好其他input的值,点击提交,将文件数据及签名等认证信息发送到form设置的action对应的页面,浏览器也会跳转到该页面。触发form表单提交数据的方式有2种,一种是在页面上点击button按钮或按钮触发,第二种是在js中执行form.submit()方法。
优点:使用简单方便,兼容性好,基本所有浏览器都支持。
缺点: 1. 提交数据后页面会跳转(下面会讲如何禁止页面跳转)。
2.因为是浏览器发起的请求,不是一个ajax,所以前端无法知道什么时候上传结束。
3. form表单里发送除文件外的数据,一般是新建一个type=hidden的input,value=‘需要传的数据’,每发送一个数据就需要一个input,一旦多了就会使得dom看起来比较冗余。
小技巧:
form表单提交数据后会自动跳转到action指定的页面,为了禁止页面跳转,可以在页面中新建一个空的ifame,比如name=‘upload’,然后设置form的target=“Uploader”,form有一个target的属性,规定在何处打开action,这样form提交数据后就会仍停留在当前页。代码如下:

<form action='uploadFile.url' enctype="multipart/form-data" type='post' target="uploaderPage">
	<input type='file'>
	<button>提交</button>
</form>
<ifrmae name='upload' id='uploaderPage'></iframe>

这样写的另一个好处是,可以知道什么时候上传完成并接收到后端的回调结果。比如上面这个例子,文件数据发送到了 ‘uploadFile.url’,假设该页面处理完数据后返回了一个地址,该地址会被写入到之前的iframe中。所以在ifame的onload函数触发时,也就是上传完成后,可以在iframe中读取到后端返回的数据。

var iframe = document.getElementById('uploadPage');
iframe.onload = function () {
	var doc = window.frames['uploaderPage'].document;
	var pre = doc.getElementsByTagName('pre');
	var obj = JSON.parse(pre[0].innerHTML);
}

使用这种方法时需要注意,iframe有跨域限制,创建出来的iframe的地址如果和当前页面地址不同源,会报错。这种情况下,建议大家在iframe的onload函数中,再次向后端请求一个接口获取文件地址,而不是直接去iframe里读取。或者返回这样的数据。

<script type="text/javascript">
	window.top.window.callback(data)
</script>

callback是和前端约定好的名字,上传完成后触发该函数并返回后端数据。

第二种:使用formData上传。(分借用form和不借用form)

借助form的ajax文件上传

<script src="jquery.min.js"></script>
<form id="uploadForm" enctype="multipart/form-data">
    <input type="file" name="file" id="file">
    <input type="button" value="Upload" id="upload" />
</form>
<script>
    $(function () {
        $('#upload').click(function () {
            $.ajax({
                url: "http://localhost:8080/img",
                type: "post",
                data: new FormData($('#uploadForm')[0]),
                cache: false,
                processData: false,
                contentType: false,
                success: function (res) {
                console.log(res)
                },
                error: function (err) {
                    console.log(err)
                }
            })
        })
    })
</script>

processData设置为false。因为data值是FormData对象,不需要对数据做处理。
<form>标签添加enctype="multipart/form-data"属性。
cache设置为false,上传文件不需要缓存。
contentType设置为false。因为是由<form>表单构造的FormData对象,且已经声明了属性enctype=“multipart/form-data”,所以这里设置为false。

不借助form的ajax文件上传

<input type="file" name="file" id="file"><input type="button" value="Upload" id="upload" />
<script src="jquery.min.js"></script>
<script>
$(function () {
    $('#upload').click(function () {
        let file = $("#file")[0].files[0];
        //创建formdata对象
        let formData = new FormData();
        formData.append("file", file);
        $.ajax({
            url: "http://localhost:8081/images",
            type: "post",
            data: formData,
            cache: false,
            processData: false,
            contentType: false,
            // headers: { 'Content-Type': 'multipart/form-data' },
            success: function (res) {
                console.log(res)
            },
            error: function (err) {
                console.log(err)
            }
        })
   })
})
</script>

append()的第二个参数应是文件对象,即$('#file')[0].files[0]
contentType也要设置为‘false’。
从代码$('#file')[0].files[0]中可以看到一个<input type="file">标签能够上传多个文件, 只需要在<input type="file">里添加multiple或multiple="multiple"属性。
用js构造form表单的数据,简单高效,但最低只兼容IE10,所以需要兼容IE9的童鞋们就略过这个方法吧。

  html:
    <input type='file'>
    js:
    var formData = new FormData();
    formData.append("userid", userid);
    formData.append("signature", signature);
    formData.append("file", file); //file是blob数据

//再用ajax发送formData到服务器即可,注意一定要是post方式上传

说明:第一种方法提到了创建多个type=‘hidden’的input来发送签名数据,这儿可以用formData.append方法来代替该操作,避免了dom中有多个input的情况出现。最后将file数据也append到formData发送到服务器即可完成上传。
优点:由于这种方式是ajax上传,可以准确知道什么时候上传完成,也可以方便地接收到回调数据。
缺点:兼容性差

扫描二维码关注公众号,回复: 6772937 查看本文章

第三种:使用fileReader读取文件数据进行上传。

HTML5的新api,兼容性也不是特别好,只兼容到了IE10。

var fr = new FileReader();
fr.readAsDataURL(file);
fr.onload = function (event) {
var data= event.target.result; //此处获得的data是base64格式的数据  
                    img.src = data;
ajax(url,{data} ,function(){})
}

上面获得的data可以用来实现图片上传前的本地预览,也可以用来发送base64数据给后端然后返回该数据块对应的地址。
优点: 同第二种
缺点:一次性发送大量的base64数据会导致浏览器卡顿,服务器端接收这样的数据可能也会出现问题

第四种:flash上传 参考jQuery封装好的uploadify插件

<div id="file_upload"></div>

html部分很简单,预留一个hook后,插件会在这个节点内部创建Flash的object,并且还附带创建了上传进度、取消控件和多文件队列展示等界面。

$(function() {
    $("#file_upload").uploadify({
   	 auto: true,
   	 method: "Post",
  	 width: 120,
   	 height: 30,
   	 swf: './uploadify.swf',
     uploader: 'http://uploadUrl',
   	 formData: {
   	 token: $("#token").val()
    },
    fileObjName: "file",
    onUploadSuccess: function(file, data, response){
    	// 根据返回结果指定界面操作
    }
    });
});

关于jQuery.uploadify可以访问了解: http://www.uploadify.com/documentation/ 。值得注意的是flash并不适合手机端应用,更好的解决方案是使用flash+html5来解决平台的兼容性问题。

二丶图片上传和预览

方法一:使用js的FileReader对象

1、FileReader对象简介

1.检测浏览器对FileReader的支持

if(window.FileReader) {
	var fr = new FileReader();
	// add your code here
}else {
	alert("Not supported by your browser!");
}

调用FileReader对象的方法
FileReader 的实例拥有 4 个方法,其中 3 个用以读取文件,另一个用来中断读取。下面的表格列出了这些方法以及他们的参数和功能,
需要注意的是 ,无论读取成功或失败,方法并不会返回读取结果,这一结果存储在 result属性中。

方法名                  参数              		描述
abort                  none            			中断读取
readAsBinaryString	   file			  		将文件读取为二进制码
readAsDataURL		   file			  		将文件读取为 DataURL
readAsText			  file, [encoding]		将文件读取为文本

readAsText:该方法有两个参数,其中第二个参数是文本的编码方式,默认值为 UTF-8。这个方法非常容易
理解,将文件以文本方式读取,读取的结果即是这个文本文件中的内容。
readAsBinaryString:该方法将文件读取为二进制字符串,通常我们将它传送到后端,后端可以通过这段字符串存储文件。
readAsDataURL:这是例子程序中用到的方法,该方法将文件读取为一段以 data: 开头的字符串,这段字符 串的实质就是 Data URL,Data URL是一种将小文件直接嵌入文档的方案。这里的小文件通常是指图像与 html 等格式的文件。(其中base64的方式就是由此来获得的。。)

  1. FileReader处理事件简介
    FileReader 包含了一套完整的事件模型,用于捕获读取文件时的状态,下面这个表格归纳了这些事件。
    onabort 中断时触发
    onerror 出错时触发
    onload 文件读取成功完成时触发
    onloadend 读取完成触发,无论成功或失败
    onloadstart 读取开始时触发
    onprogress 读取中
    文件一旦开始读取,无论成功或失败,实例的 result 属性都会被填充。如果读取失败,则 result 的值为 null ,否则即是读取的结果,绝大多数的程序都会在成功读取文件的时候,抓取这个值。

     <p>
         <label>请选择一个文件:</label>
         <input type="file" id="file" />
         <input type="button" value="读取图像" onclick="readAsDataURL()" />
         <input type="button" value="读取二进制数据" onclick="readAsBinaryString()" />
         <input type="button" value="读取文本文件" onclick="readAsText()" />
     </p>
     <div id="result" name="result"></div>
    
    
     <script type="text/javascript">
         var result = document.getElementById("result");
         var file = document.getElementById("file");
         //判断浏览器是否支持FileReader接口
         if (typeof FileReader == 'undefined') {
             result.InnerHTML = "<p>你的浏览器不支持FileReader接口!</p>";
             //使选择控件不可操作
             file.setAttribute("disabled", "disabled");
         }
    
         function readAsDataURL() {
             //检验是否为图像文件
             var file = document.getElementById("file").files[0];
             if (!/image\/\w+/.test(file.type)) {
                 alert("看清楚,这个需要图片!");
                 return false;
             }
             var reader = new FileReader();
             //将文件以Data URL形式读入页面
             reader.readAsDataURL(file);
             reader.onload = function (e) {
                 var result = document.getElementById("result");
                 //显示文件
                 result.innerHTML = '<img src="' + this.result + '" alt="" />';
             }
         }
    
         function readAsBinaryString() {
             var file = document.getElementById("file").files[0];
             var reader = new FileReader();
             //将文件以二进制形式读入页面
             reader.readAsBinaryString(file);
             reader.onload = function (f) {
                 var result = document.getElementById("result");
                 //显示文件
                 result.innerHTML = this.result;
             }
         }
    
         function readAsText() {
             var file = document.getElementById("file").files[0];
             var reader = new FileReader();
             //将文件以文本形式读入页面
             reader.readAsText(file);
             reader.onload = function (f) {
                 var result = document.getElementById("result");
                 //显示文件
                 result.innerHTML = this.result;
             }
         }
    
     </script>
    

3 、使用js的FileReader对象实现上传图片时的图片预览功能

<!DOCTYPE html>
<html>

<head>
    <meta name="viewport" content="width=device-width,initial-scale=1, user-scalable=no">
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <meta name="format-detection" content="telephone=no">
    <title>test</title>
    <script>
        //选择图片时预览功能
        function imageshow(source) {
            var file = source.files[0];
            var imageid = source.id;
            if (window.FileReader) {
                var fr = new FileReader();
                fr.onloadend = function (e) {
                    document.getElementById("portrait" + imageid).src = e.target.result;
                };
                fr.readAsDataURL(file);
            }
            document.getElementById("image" + imageid).style.display = "none";
            document.getElementById("show" + imageid).style.display = "block";
        }
    </script>
</head>

<body>
    <div>
        <div id="image1">
                  <p>上传截图</p>
            <input type="file" name="screenshot1" id="1" onchange="imageshow(this)" />
        </div>
            <div id="show1" style="display:none;">
                  <img src="" id="portrait1" width="100" height="70">
                </div>
            <div id="image2">
            <p>上传截图</p>
            <input type="file" name="screenshot2" id="2" onchange="imageshow(this)" />
        </div>
            <div id="show2" style="display:none;">
                  <img src="" id="portrait2" width="100" height="70">
               </div>
        <div id="image3">
            <p>上传截图</p>
            <input type="file" name="screenshot3" id="3" onchange="imageshow(this)" />
        </div>
          <div id="show3" style="display:none;">
                  <img src="" id="portrait3" width="100" height="70">
                </div>
    </div>
</body>

</html>

方法二:使用window.createObjectURL
直接上代码:

<!DOCTYPE html>
<html>

<head>
    <title>图片上传预览</title>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <script src="http://www.codefans.net/ajaxjs/jquery-1.6.2.min.js"></script>
</head>

<body>
    <form name="form0" id="form0">
        <input type="file" name="file0" id="file0" multiple="multiple" />
        <br>
        <img src="" width="100" height="100" id="img0">
    </form>
    <script>
        $("#file0").change(function () {
            var objUrl = getObjectURL(this.files[0]);
            console.log("objUrl = " + objUrl);
            if (objUrl) {
                $("#img0").attr("src", objUrl);
            }
        });

        //取得该文件的url function getObjectURL(file) {
        var url = null;
        if (window.createObjectURL != undefined) {
            url = window.createObjectURL(file);
        } else if (window.URL != undefined) {
            url = window.URL.createObjectURL(file);
        } else if (window.webkitURL != undefined) {
            url = window.webkitURL.createObjectURL(file);
        }
        return url;
//}
    </script>
</body>

</html>

猜你喜欢

转载自blog.csdn.net/VIP__ID/article/details/93484347