form配合iframe实现文件异步上传
2017-08-23 00:00
309 查看
摘要: form配合iframe实现文件异步上传
JavaScript
JavaScript
后台代码 (Python方式实现)
JavaScript 提取的公共方法 utils.js
utils.js 对应的源文件 CoffeeScript
简述
使用form和iframe实现异步上传文件的功能
原理
form表单可以上传文件,但是提交form表单会打开新页面或刷新页面,为了不刷新页面,将form指向一个隐藏的iframe,form提交后它所指向的iframe会重新加载,iframe的内容即为服务器返回的内容。
优点
兼容各种浏览器各个版本的文件异步上传
缺点
如果要上传的文件需要校验(类型,大小),对于无法获取files属性的浏览器而言,用户体验性不好。
文件需要校验(类型,大小)的处理
能够获取到files就在前台校验,否则后台校验。
示例代码
HTML<input type="file" name="file" />
JavaScript
$(function(){ /* 监听change事件 */ $('input[name=file]').on('change', function(e){ var $target = $(e.target); /* 获取/创建 iframe */ var $frame = $('iframe[name=upload_frame]'); if(!$frame.length){ $frame = $('<iframe>', {name: 'upload_frame', style: 'display: none;'}); } /* 创建form */ var $form = $('<form>', { method: 'POST', // post方式提交 action: 'sever_address', // 文件上传的服务器地址 target: 'upload_frame', // 指向iframe enctype:'multipart/form-data' // 向服务器发送二进制数据 }); /* 嵌套form */ $target.wrap($form) /* 提交表单 */ $target.parent().submit(); /* 处理回调 */ $frame.on('load', function(){ /* 去除嵌套的form */ $target.parent().replaceWith($target); /* 接收服务器返回的数据 */ var resp = $frame.contents().text(); try { resp = JSON.parse(resp); /* 提示上传成功?按理说接下的代码才是真正的回调 */ } catch (error) { console.error(error); } }); }); });
完整的示例
HTML<input type="file" name="file" />
JavaScript
$(function(){ var utils = new this.Utils(); $('input[type=file]').on('change', function(e){ utils.uploadQiNiu({ $target: $(e.target), # 文件选择器 prefix: 'subjective/', # 前缀 limitSize: 5, # 限制文件最大为5M limitType: ['png', 'jpg'], # 限制文件类型, callback: function(uri){ utils.showMsg('上传成功: ' + uri); } }); }); })
后台代码 (Python方式实现)
def upload_file(request): # 返回信息 def render(msg_='上传失败', uri_='', name_='', type_=''): return HttpResponse( content=json.dumps({ 'uri': uri_, 'msg': msg_, 'name': name_, 'type': type_, }), content_type="text/html;charset=utf-8", status=200 ) # 获取文件 file_obj = request.FILES.get('file', None) # 无文件对象的处理 if not file_obj: return render("请选择文件!") post_vars = request.POST file_type = file_obj.content_type # 判断是否需要验证(类型,大小) if post_vars.get('validate', False): # 验证文件大小 limit_size = int(post_vars.get('limitSize', 0)) if limit_size > 0 and file_obj.size > limit_size * 1024 ** 2: return render('文件大小不能超过{}M!'.format(limit_size)) # 验证文件类型 limit_type = post_vars.get('limitType', '') reg = re.compile(file_type, re.I) if limit_type and not reg.match(limit_type.replace(',', '|')): return render('类型不符, 请上传{}格式的文件!'.format(limit_type)) # 验证文件后缀 suffix_type = post_vars.get('suffixType', '') if suffix_type: file_type = file_obj.name.split('.').pop() reg = re.compile(file_type, re.I) if not reg.match(suffix_type.replace(',', '|')): return render('类型不符, 请上传{}格式的文件!'.format(suffix_type)) filename = file_obj.name prefix = post_vars.get('prefix', '') timestamp = int(time.time()) key = '{}{}{}'.format(prefix, timestamp, filename) # 获取配置信息 access_key = settings.QINIU_ACCESS_KEY secret_key = settings.QINIU_SECRET_KEY bucket = settings.QINIU_CMS_RESOURCE_BUCKET host = settings.QINIU_CMS_RESOURCE_URL # 获取上传凭证 token = Auth(access_key, secret_key).upload_token(bucket, key, 7200) # 上传到七牛 try: ret, info = put_data( token, key, file_obj.read(), mime_type=file_obj.content_type ) uri = '{}/{}'.format(host, ret['key']) msg = '上传成功' except Exception as ex: logging.error(ex) uri = '' msg = '上传失败' return render(msg, uri, filename, file_type)
JavaScript 提取的公共方法 utils.js
// Generated by CoffeeScript 1.12.4 (function() { var bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }; this.Utils = (function() { function Utils() { this.bodyLock = bind(this.bodyLock, this); this.showLoading = bind(this.showLoading, this); this.confirmMsg = bind(this.confirmMsg, this); this.showMsg = bind(this.showMsg, this); this.uploadQiNiu = bind(this.uploadQiNiu, this); } Utils.prototype.uploadQiNiu = function(options) { var $form, $frame, $target, file, fileType, files, limitSize, limitType, settings, suffixType; settings = { $target: null, prefix: 'project/', limitSize: 0, limitType: [], suffixType: [], callback: (function(_this) { return function() {}; })(this) }; $.extend(settings, options); $target = settings.$target; if (!$target) { console.error('Missing "$target" in settings'); return false; } files = $target[0].files; if (files) { file = files[0]; if (file == null) { this.showMsg('请选择文件!'); return false; } limitSize = parseFloat(settings.limitSize); if (limitSize > 0 && file.size > limitSize * 1024 * 1024) { this.showMsg("文件大小不能超过" + limitSize + "M!"); $target.val(''); return false; } limitType = settings.limitType; fileType = file.type.toLowerCase(); if (limitType.length && !fileType.match(eval("/" + (limitType.join('|')) + "/"))) { this.showMsg("类型不符, 请上传" + limitType + "格式的文件!"); $target.val(''); return false; } suffixType = settings.suffixType; if (suffixType.length) { fileType = file.name.split('.').pop().toLowerCase(); if (!fileType.match(eval("/" + (suffixType.join('|')) + "/"))) { this.showMsg("类型不符, 请上传" + suffixType + "格式的文件!"); $target.val(''); return false; } } } this.showLoading('正在上传...'); $frame = $('iframe[name=upload_frame]'); if (!$frame.length) { $frame = $('<iframe>', { name: 'upload_frame', style: 'display: none' }); $(document.body).append($frame); } $frame.on('load', (function(_this) { return function() { var resp; _this.bodyLock(false); $target.parent().replaceWith($target); resp = $frame.contents().text(); if (resp.indexOf('413 Request Entity Too Large') !== -1) { _this.showMsg('上传文件过大!'); console.error('413 Request Entity Too Large'); return; } resp = JSON.parse(resp); _this.showMsg(resp.msg); return settings.callback(resp.uri, resp.name, (files ? fileType : resp.type), resp.msg); }; })(this)); $target.attr('name', 'file'); $form = $('<form>', { method: "post", name: "upload_form", target: "upload_frame", action: "/qi_niu_upload/", enctype: "multipart/form-data", style: 'display:none' }); $target.wrap($form); $target.after("<input type='hidden' name='prefix' value='" + settings.prefix + "'>"); if (!files) { $target.after("<input type='hidden' name='validate' value='True'>"); $target.after("<input type='hidden' name='limitSize' value='" + settings.limitSize + "'>"); $target.after("<input type='hidden' name='limitType' value='" + settings.limitType + "'>"); $target.after("<input type='hidden' name='suffixType' value='" + settings.suffixType + "'>"); } $target.parent().submit(); }; Utils.prototype.showMsg = function(msg, timeout) { if (timeout == null) { timeout = 1000; } return $.jBox.tip(msg, '', { timeout: timeout }); }; Utils.prototype.confirmMsg = function(msg, fun) { return $.jBox.confirm(msg, '提示', (function(_this) { return function(v) { if (v === 'ok') { return fun(); } }; })(this)); }; Utils.prototype.showLoading = function(msg) { $.jBox.tip(msg, 'loading'); $('.jbox-fade').css('height', ($(document).height()) + "px"); return this.bodyLock(true); }; Utils.prototype.bodyLock = function(lock) { var body, flag; body = $('body'); flag = lock ? 'hidden' : 'auto'; return body.css('overflow', flag); }; return Utils; })(); }).call(this);
utils.js 对应的源文件 CoffeeScript
class @Utils # 上传文件 uploadQiNiu: (options) => settings = $target: null # 文件选择器 prefix: 'project/' # 七牛空间前缀 limitSize: 0 # 限制大小 limitType: [] # 文件类型 suffixType: [] # 后缀类型 callback: () => # 回调函数 # 配置信息 $.extend settings, options # 判断文件选择器是否存在 $target = settings.$target if not $target console.error 'Missing "$target" in settings' return false files = $target[0].files # 能获取到files属性 if files file = files[0] # 判断是否选中文件 if not file? @showMsg '请选择文件!' return false # 判断是否需要限制文件大小 limitSize = parseFloat settings.limitSize if limitSize > 0 and file.size > limitSize * 1024 * 1024 @showMsg "文件大小不能超过#{limitSize}M!" $target.val '' return false # 判断是否需要限制文件类型 limitType = settings.limitType fileType = file.type.toLowerCase() if limitType.length and not fileType.match eval "/#{limitType.join '|'}/" @showMsg "类型不符, 请上传#{limitType}格式的文件!" $target.val '' return false # 判断是否需要限制文件后缀 suffixType = settings.suffixType if suffixType.length fileType = file.name.split('.').pop().toLowerCase() if not fileType.match eval "/#{suffixType.join '|'}/" @showMsg "类型不符, 请上传#{suffixType}格式的文件!" $target.val '' return false @showLoading '正在上传...' $frame = $ 'iframe[name=upload_frame]' if not $frame.length $frame = $ '<iframe>', name: 'upload_frame' style: 'display: none' $(document.body).append $frame $frame.on 'load', () => @bodyLock false $target.parent().replaceWith($target) resp = $frame.contents().text() if resp.indexOf('413 Request Entity Too Large') != -1 @showMsg '上传文件过大!' console.error('413 Request Entity Too Large') return resp = JSON.parse resp @showMsg resp.msg settings.callback resp.uri, resp.name, (if files then fileType else resp.type), resp.msg # 后台获取文件的key为file $target.attr 'name', 'file' $form = $ '<form>', method: "post" name: "upload_form" target: "upload_frame" action: "/qi_niu_upload/" enctype: "multipart/form-data" style: 'display:none' # 外层包装form $target.wrap($form) $target.after("<input type='hidden' name='prefix' value='#{settings.prefix}'>") if not files $target.after("<input type='hidden' name='validate' value='True'>") $target.after("<input type='hidden' name='limitSize' value='#{settings.limitSize}'>") $target.after("<input type='hidden' name='limitType' value='#{settings.limitType}'>") $target.after("<input type='hidden' name='suffixType' value='#{settings.suffixType}'>") $target.parent().submit() return # 提示信息 showMsg: (msg, timeout=1000) => $.jBox.tip msg, '', {timeout: timeout} # 确认窗口 confirmMsg: (msg, fun) => $.jBox.confirm msg, '提示', (v) => if v is 'ok' fun() # 加载中 showLoading: (msg) => $.jBox.tip msg, 'loading' $('.jbox-fade').css 'height', "#{$(document).height()}px" @bodyLock true # 设置body是否可以滚动 bodyLock: (lock) => body = $ 'body' flag = if lock then 'hidden' else 'auto' body.css 'overflow', flag
相关文章推荐
- form配合iframe实现文件异步上传
- php+html(form+iframe)实现文件的异步上传
- form、iframe实现异步上传文件
- iframe标签实现form表单提交(如文件上传下载)不刷新
- 使用jquery.form.js+servlet实现文件异步上传
- 注意这个细节——————target = iframe 实现异步上传文件效果
- jQuery实现jQuery-form.js实现异步上传文件
- Asp.net + js 异步上传文件的例子 - 使用iframe实现
- 两种文件上传的实现-Ajax上传和form+iframe
- 关于PHP+iFrame实现页面无需刷新的异步文件上传
- PHP+iFrame实现页面无需刷新的异步文件上传
- PHP用iframe实现文件异步上传(无刷新)
- html使用iframe实现伪异步表单,实现无刷新上传文件时遇到的问题
- FormData可实现异步传输二进制文件(即异步文件上传)
- ajax+php (jquery.form插件)实现异步文件上传
- Django+Jquery+Bootstrap Modal+Iframe使用异步机制上传文件实现方法
- 详解Ajax和form+iframe 实现文件上传的方法(两种方式)
- 两种文件上传的实现-Ajax上传和form+iframe
- 用xmlhttp将html的数据打包成multipart/form-data格式,实现异步上传文件功能
- 用FormData实现无刷新页面异步上传文件