前端文件上传方式

 一丶前端文件上传方式

前端网页文件上传一般使用 <input type="file" />来实现。

    在 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按钮或<input type='submit'>按钮触发,第二种是在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上传,可以准确知道什么时候上传完成,也可以方便地接收到回调数据。

缺点:兼容性差

第三种:使用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的方式就是由此来获得的。。)

2. 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>

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,265评论 6 490
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,078评论 2 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 156,852评论 0 347
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,408评论 1 283
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,445评论 5 384
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,772评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,921评论 3 406
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,688评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,130评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,467评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,617评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,276评论 4 329
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,882评论 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,740评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,967评论 1 265
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,315评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,486评论 2 348

推荐阅读更多精彩内容

  • (纯js的质量压缩,非长宽压缩) 此demo为大于1M对图片进行压缩上传 若小于1M则原图上传,可以根据自己实际需...
    丨ChenSir丨阅读 978评论 0 1
  • 前端无法像原生APP一样直接操作本地文件,否则的话打开个网页就能把用户电脑上的文件偷光了,所以需要通过用户触发,用...
    雷波_viho阅读 821评论 0 1
  • 单例模式 适用场景:可能会在场景中使用到对象,但只有一个实例,加载时并不主动创建,需要时才创建 最常见的单例模式,...
    Obeing阅读 2,056评论 1 10
  • mean to add the formatted="false" attribute?.[ 46% 47325/...
    ProZoom阅读 2,694评论 0 3
  • 用手艺穿透知识,日课的习惯,就是肆意训练的累积。 比如投资,看似简单,日复一日的看有标准要求的财报,但久而重复,把...
    捡石头的村童阅读 129评论 0 0