图片上传兼容IE浏览器无需jquery插件

2019-08-0879次阅读javascript原生Js

网上搜了一下,无非就是基于flash组件、juqery插件来完成,基于您可能不需要jquery,想试一下javascrpit原生图片上传。

 

文件上传

 

1、传统形式

文件上传的传统形式,是使用表单元素file:

<form id="upload-form" action="upload.php" method="post" enctype="multipart/form-data" >

    <input type="file" id="upload" name="upload" /> <br />

    <input type="submit" value="Upload" />

</form>

传统的表单上传,属于"同步上传"。也就是说,点击上传按钮后,网页"锁死",用户只能等待上传结束,然后浏览器刷新,跳到表单的action属性指定的网址。

 

2、iframe上传

iframe上传为异步方式,主要是表单添加target属性,用户点击submit时,指向iframe窗口。

<form id="upload-form" target="update_img" action="/upload?type=iframe&flag=7&callback=getImgSrc" method="post" enctype="multipart/form-data">
    <input type="file" class="ieinput" id="ieinput" name="FileUploadForm[file]">
    <input type="submit" value="Upload">
</form>

<iframe frameborder="0" scrolling="no" id="update_img" name="update_img" src="about:blank" style="height:0;width:0;overflow:hidden;"></iframe>

这使得上传结束后,服务器将结果返回iframe窗口,所以当前页面就不会跳转了。其次,它在action属性指定的上传网址的后面,添加了一个参数,使得服务器知道回调函数的名称。这样就能将服务器返回的信息,从iframe窗口传到上层页面。
服务器(upload.php)返回的信息,应该是如下形式:

<script type="text/javascript">

  window.top.window['callback'](data);

</script>


3、ajax上传

HTML5提出了XMLHttpRequest对象的第二版,从此ajax能够上传文件了。这是真正的"异步上传",是将来的主流。上面的iframe上传,可以用作老式浏览器的替代方案。ajax上传主要用的是FormData对象,它能够构建类似表单的键值对。

// 检查是否支持FormData
  if(window.FormData) { 

    var formData = new FormData();

    // 建立一个upload表单项,值为上传的文件
    formData.append('upload', document.getElementById('upload').files[0]);

    var xhr = new XMLHttpRequest();

    xhr.open('POST', $(this).attr('action'));

    // 定义上传完成后的回调函数
    xhr.onload = function () {

      if (xhr.status === 200) {

        console.log('上传成功');

      } else {

        console.log('出错了');

      }

    };

    xhr.send(formData);

    }

关于图片上传中的进度条、图片预览、拖放上传请移步阮老师的文件上传的渐进式增强

 

实操

1、ajax上传需要用到FormData对象,它的兼容性IE堪忧。

所以需要判断是IE浏览器版本使用iframe上传。

const isIe = function(){

    return (navigator.userAgent.indexOf("Edge") == -1) && ( !!window['ActiveXObject'] || "ActiveXObject" in window );

}();

 

2、项目中本来就是一个原生form提交表单,而iframe上传图片也需要一个form,所以页面结构大体是这样的,在form外再放一个form

<form target="_self" enctype="multipart/form-data" id="account" action="/create/19" method="post">
    <div class="kfstit"><h3>帐号修改内容</h3></div>
  
    <table class="tableForm">
            .....
            <tr>
                <th>手持身份证照片</th>
                <td>
                    <span class="upfiles">
                        <i class="uppr">
                            <input type="file" accept="image/jpeg,image/jpg,image/png" id="fileupload" name="FileUploadForm[file]" multiple>
                            <label class="Iechange" for="ieinput"></label>
                        </i>
                    </span>
                    <span class="musts">*</span>
                    <span class="formTips"></span>
                </td>
            </tr>
            ......
    </table>

   
    <div class="kfstit"><h3>联系方式</h3></div>
    <table class="tableForm">
            .....
    </table>
</form>

<form id="upload-form" target="update_img" action="/upload?type=iframe&flag=7&callback=uploadResult" method="post" enctype="multipart/form-data">
    <input type="file" class="ieinput" id="ieinput" name="FileUploadForm[file]">
</form>

<iframe frameborder="0" scrolling="no" id="update_img" name="update_img" src="about:blank" style="height:0;width:0;overflow:hidden;"></iframe>

ajax上传用真正的ID为fileupload的input触发,IE下用ID为ieinput的lable标签来触发。

//如果是IE浏览器给uppr父标签添加ie类名,让label显示,input标签隐藏
if(isIe) query.addClass(query.getByClass('uppr',this.wrap)[0],'ie');
    
query.add(document.getElementById('fileupload'),'change',event=>{

    this.changeInput( query.getTarget(event) );

});

private async changeInput(target){

        if(!target && !target.files) return;

        query.forEach(target.files,item=>{

            if(item.size > 1024*1024*2){

                //...照片大小大于2M,请重新选择照片!
                
            }else{

               const fd = new FormData();

               fd.append('flag', '7');

               fd.append('FileUploadForm[file]',item);
                        
               const data = await post({
                   url:'/upload',
                   data:fd
                })
// [
//     {
//         size: 122388,
//         url: "/static/27ca29f827598a4c6e683f0ad70a92c20ca4d238.jpg"
//     }
// ]

            }

        });

           
}

这里的query是一个自定义js常用基础库

 

3、IE9及以下上传附件时报***.submit()拒绝访问?

刚开始ID为ieinput的lable标签,其实是一个span标签,通过点击span标签。来触发外面form里file.click()弹出文件选择控件。这时在E9及以下报***.submit()拒绝访问?网上的说法是file.click()会触发浏览器js安全性问题所以拒绝。灵光闪动利用lable的for来触发file的change事件试试:

query.add(document.getElementById('ieinput'),'change',event=>{

    const target = query.getTarget(event);

    if(target.value) (<HTMLFormElement>document.getElementById('upload-form')).submit();

});
window['uploadResult'] = data=>{
// [
//     {
//         size: 122388,
//         url: "/static/27ca29f827598a4c6e683f0ad70a92c20ca4d238.jpg"
//     }
// ]        
   
}

这里的query是一个自定义js常用基础库

 

4、文件上传multipart/form-data

这里要注意的细节ajax上传时,send参数一定是一个formData对象,而不是把formData对象序列化get网址传递,当send一个formData对象时浏览器会自动设置Content-Type字段为multipart/form-data。

xhr.send(formData);

 

5、因为项目时间紧,只做了图片上传功能,关于图片预览功能也可参考司徒正美的前端图片预览,上传前预览,兼容IE7、8、9、10、11,Firefox,Chrome

上一篇: 重绘Repaint和回流Reflow以及如何进行优化  下一篇: 收藏2个VUE表单数据验证组件  

图片上传兼容IE浏览器无需jquery插件相关文章