iframe方法实现表单文件上传,页面无刷新

表单上传

需求:

  • 网站需要安装控件,只能在IE中打开
  • 实现数据(字符串、文件)的上传
  • 上传时通过图片验证码,文件大小、格式验证
  • 兼容IE8+

一开始不知道网站只能在IE中打开,而且还得兼容IE8。初始的方法使用的是ajaxFormData()inputFileList属性,可以通过这个FileList获取文件的文件名文件大小文件类型

var formData = new FormData();
formData.append("name", $("[name=username]").val()); // 字符串
...
formData.append("file", document.getElementById("file").files[0]); // 文件

$.ajax({
  url: urlStr,
  type: "POST",
  data: formData,
  processData: false,
  contentType: false,
  success: function (data) {},
  error: function(error)
})

使用点:

  • XMLHttpRequest Level 2新增的FormData,兼容性为IE10+
  • input标签typefile时的files属性,兼容性为IE10+

FormData     input file属性


遇到的兼容问题:

  1. IE89无法读取文件的FileList属性,也就无法获取文件的大小和MIME
  2. 图片验证码时使用input事件,当输入的内容trim()后长度等于4时,发送验证请求,IE8对onInput不支持(兼容性查看),
  3. 模拟表单按钮,点击label时无法唤起display: none;input

分析:
无法使用ajax的FormData,那只能使用浏览器原生的Form功能。

<form 
  class="pure-form pure-form-aligned"
  action="/cos/rest/complain/advice.json"
  method="POST"
  target="formsubmit"
  enctype="multipart/form-data" 
  onsubmit="return funcFormCheck();"></form>

action指向后台提供的接口
method设置HTTP的方式
target后台返回的数据写入target的页面,这里面写入本地隐藏的一个iframe,通过给这个iframe绑定load事件去获取里面的内容,类似ajax中successdata
enctype设置form上传的格式,默认为application/x-www-form-urlencoded(将参数附到url后面,类似baidu.com/?name=hell
onsubmit表单提交前触发,可以通过这个属性做JS方面的验证,建议看这篇blog,从prototype分析该属性。

ps:

  • 有些情况下,后台返回的JSON文件会被IE浏览器下载,而不是写在iframe里。那是因为IE浏览器不支持application/json形式文件。此处可以让后台同学设置返回json文本的contentTypetext/html
  • IE8不支持input的onInput事件,无法在输入验证码时无痛验证,此处通过给当前input绑定keyup事件,来准确监听value的长度,并发出验证请求。
  • 为了避免空格出现影响字符长度判断,使用trim(),但是IE8不支持trim(),通过向Stringprototype添加trim()方法
  • 我们可以通过FileList属性获取文件的MIME,通过我们也可以在<input type="file" accept="image/*, text/*"> accept属性直接限制,但是IE89不支持该属性。
<!--提供输入框验证插件,如果验证通过则返回true-->
<script src="/etc/designs/gtja_v2/default/themes/js/formValid2.js"> </script>

<!--提示框插件-->
<script src="/etc/designs/gtja_v2/default/shared/clientlibs/js/plugin/layer/layer.js"></script>
<script src="/etc/designs/gtja_v2/default/themes/js/base64.js"></script>
<iframe name="formsubmit" id="formsubmit" style="display: none"></iframe>
<div class="inside form-complain">
    <div class="formbox">
        <h3>投诉与建议内容</h3>
        <form 
            class="pure-form pure-form-aligned"
            action="/cos/rest/complain/advice.json"
            method="POST"
            target="formsubmit"
            enctype="multipart/form-data" 
            onsubmit="return funcFormCheck();">
            <input class="login-token" type="hidden" name="loginToken">
            <div class="pure-control-group">
                <div class="input-label">
                    <em class="red">*</em> 您的姓名:</div>
                <input class="ele-input" name="name" type="text" data-valid-list="" data-type="noEmpty" placeholder="请输入您的姓名">
                <span class="error-place"></span>
            </div>
            <div class="pure-control-group">
                <div class="input-label">
                    <em class="red">*</em> 联系电话:</div>
                <input class="ele-input" name="phoneNo" type="text" data-valid-list="" data-type="phone" placeholder="请输入您的联系电话">
                <span class="error-place"></span>
            </div>
            <div class="pure-control-group">
                <div class="input-label">
                    <em class="red">*</em> 邮箱地址:</div>
                <input class="ele-input" name="mailAddr" type="text" data-valid-list="" data-type="email" placeholder="请输入您的邮箱">
                <span class="error-place"></span>
            </div>
            <div class="pure-control-group">
                <div class="input-label">
                    <em class="red">*</em> 反馈概要:</div>
                <input class="ele-input" name="desc" type="text" data-valid-list="" data-type="noEmpty" placeholder="请输入您要反馈的主题">
                <span class="error-place"></span>
            </div>
            <div class="pure-control-group">
                <div class="input-label">
                    <em class="red">*</em> 反馈内容:</div>
                <textarea class="ele-textarea" name="content" maxlength="200" placeholder="请详细说明您要反馈的问题或为我们提供建议" data-valid-list="" data-type="noEmpty"></textarea>
                <span class="error-place"></span>
            </div>
            <div class="pure-control-group">
                <div class="input-label"> 附件上传:</div>
                <label class="labelFile" style="background-color:#004e98;color:#ffffff" for="file">点击上传文件</label>
                <span class="error-place filename"></span>
                <input name="file" id="file" class="file hide" type="file" placeholder="上传附件">
                <img class="icon-del" src="/etc/designs/gtja_v2/default/themes/images/icon-remove.png" alt="删除文件">
                <span style="display:block;margin-left:160px;color:#b2b2b2;font-size:11px">(如有附件可进行上传,不超过5MB,可上传docx,doc,xls,jpg等格式文件)</span>
            </div>
            <div class="pure-control-group">
                <div class="input-label">
                    <em class="red">*</em> 验证码:</div>
                <input id="foo" class="foo ele-input" type="text" placeholder="">
                <img class="captchaImage" src="http://180.163.109.16/cos/rest/stock/captchaImage" height="32" width="100" onclick="changeCaptcha(this)" title="看不清楚?点击换一张">
                <span class="error-place"></span>
            </div>
            <div class="pure-controls">
                <input type="submit" class="pure-button pure-button-primary btn-sub" value="提交">
                <input type="reset" class="pure-button" value="重置">
            </div>
        </form>
    </div>
</div>
<script>
    String.prototype.trim = function() {  
        return this.replace(/(^\s*)|(\s*$)/g, "");  
    } 
    var urlStr = "";
    var address = $.base64.btoa(encodeURIComponent(location.protocol + '//' + location.host + '/cos/rest/complain/transport'));
    $(document).ready(function() {
        $.ajax({
            url: urlStr+"/cos/rest/complain/checkLogin.json",
            dataType: 'json',
            success: function (data) {
                if (data.isLogin === false) {
                    layer.open({
                        title: '提示',
                        content: '您当前还未登录,请登录后重试',
                        success: function (index, layero){
                            window.setTimeout(function (){
                                window.location.href = 'http://mall.gtja.com/loginweb/login?nextUrl=' + address;
                            },2000)
                        },
                        yes: function (index, layero) {
                            window.location.href = 'http://mall.gtja.com/loginweb/login?nextUrl=' + address;
                        }
                    });
                } 
            },
            error: function (error, status) {
                    layer.open({
                        title: '提示',
                        content: '服务器或网络错误,请登录后重试',
                        success: function (index, layero){
                            window.setTimeout(function (){
                                window.location.href = address;
                            },2000)
                        },                                    
                        yes: function (index, layero) {
                            window.location.href = address;
                        }
                    });
            }
        })     
    });
    function getLoginToken() {
        var str = location.search;
        var equalIndex = str.indexOf('=');
        return str.substr(equalIndex + 1)
    }
    $(".login-token").val(getLoginToken());
    function funcFormCheck() {
        if ($(".formbox").formValid() && imgVerifyFlag && fileVerifyFlag) {
            return true;
        } else {
            return false;
        }
    }
    $("#formsubmit").load(function() {
        var SbodyContent = $(window.frames['formsubmit'].document.body).text();
        if(SbodyContent !== '') {
            var oBodyContent = JSON.parse(SbodyContent)
            if (oBodyContent.isLogin === true) {
                if (oBodyContent.sendStatus === true) {
                    layer.open({ title: '提示', content: '投诉与建议内容发送成功' });
                } else {
                    layer.open({ title: '提示', content: '投诉与建议内容发送失败,请重试' });
                }

            } else {
                layer.open({
                    title: '提示',
                    content: '登录超时,请登录后重试',
                    yes: function (index, layero) {
                        window.location.href = address;
                    }
                });
            }
        }
    });
    var checkCodeUrl = urlStr + '/cos/rest/stock/checkCode.json';
    var imgVerifyFlag = false;
    // 切换图片二维码
    function changeCaptcha(obj) {
        obj.src = urlStr + "/cos/rest/stock/captchaImage?" + Math.random();
    }
    $(".foo").on("keyup", function () {
        var $this = $(this);
        imgVerifyFlag = false;
        if ($this.val().trim().length === 4) {
            $.ajax({
                url: checkCodeUrl,
                data: {
                    captcha: $this.val()
                },
                dataType: 'json',
                success: function (data) {
                    if (data.verification === false) {
                        imgVerifyFlag = false
                        layer.open({ title: '提示', content: '请输入正确的图片验证码' });
                    } else {
                        imgVerifyFlag = true
                    }
                },
                error: function (error, status) {
                    layer.open({ title: '提示', content: '网络错误,请点击图片验证码,获取新的验证码' });
                }
            })
        }
    });
    var fielRep = /image|wordprocessingml|spreadsheetml|excel|msword/
    var fileVerifyFlag = true
    $("#file").on("change", function () {
        var $this = $(this);
        fileVerifyFlag = false;
        if (this.files !== undefined && this.files.length > 0) {
            var fileObj = this.files[0];
            if ((fileObj.size / 1024 / 1024) > 5 || !fielRep.test(fileObj.type)) {
                layer.open({ title: '提示', content: '请上传不大于5M的word文档,表格或者图片' });
                $this.val('');
                fileVerifyFlag = true
            } else {
                fileVerifyFlag = true
                $(".filename").text(fileObj.name);
                $(".filename").show();
                $(".icon-del").show();
            }
        } else {
            var path = $this.val();
            var fakeLen = 'fakepath'.length;
            var fName = path.substr(path.indexOf('fakepath') + fakeLen + 1);
            fileVerifyFlag = true;
            $(".filename").text(fName);
            $(".filename").show();
            $(".icon-del").show();
        }
    });
    $(".icon-del").on("click", function () {
        $(".icon-del").hide();
        $(".filename").text('').hide();
        $("#file").val('');
        fileVerifyFlag = true;
    });
    $("[type=reset]").on("click", function () {
        $(".filename").text('').hide();
        $(".captchaImage").attr("src",urlStr + "/cos/rest/stock/captchaImage?" + Math.random());
    })
</script>

总结:
我们长期使用ajax和一些高级特性,以至于我们忘了在上古时代传统的Form表单还有那么多的特性。HTML还需要好好看看。
忘了说了文件的大小和媒体类型,在IE89下没有获取,如果要获取的话需要使用IE自带的activex诸多麻烦,就舍弃了。


参考文章:
从原型角度讲解onsubmit
IE直接下载json文件的原因
IE支持的文件媒体类型
向mdn致谢,html、js知识点都是从上面找的

猜你喜欢

转载自blog.csdn.net/a562550212/article/details/78964387