番外篇:jQuery表单库jquery.form.js
本主题是《云客drupal源码分析》的番外篇,在drupal系统中用于支持AJAX API,由于这是一个独立实用的库,因此专门用一个主题介绍
简介:
jQuery表单库(jquery.form.js库)以jQuery为基础,用于处理表单AJAX提交,使得表单AJAX提交简单、容易,且能完整控制提交过程和处理结果,不需要任何特殊标签辅助,不影响原表单结构,只要使用该库就能使普通表单平滑升级为ajax提交表单
官方地址:https://github.com/jquery-form/form
源代码查看和下载地址:https://github.com/jquery-form/form/blob/master/src/jquery.form.js
当前(201907)版本4.22
该版本对jquery的兼容性:
需要jQuery 1.7.2或更高,完全兼容jQuery 2,部分兼容jQuery 3,本篇测试环境为jquery 3.2.1,测试无问题,不兼容jQuery 3 Slim
drupal8.7版本该库版本4.22及jquery 3.2.1
使用示例
先看一个使用示例整体感受下其魅力:
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>jquery表单示例</title>
<script src="jquery.min.js"></script>
<script src="jquery.form.js"></script>
</head>
<body>
<button id="toSubmit">立即提交表单,结果显示在页头</button>
<div id="yk1"></div>
<form name="f" id="f" action="index.php" target="_blank">
云客:<input type="text" name="yunke"><br>
标题:<input type="text" name="title">
<input type="submit" name="sub" value="提交">
</form>
<div id="yk2"></div>
<script type="text/javascript">
$(function () {
$("#f").ajaxForm({
target: '#yk2', //正常的表单提交结果显示在页尾
});
});
document.getElementById('toSubmit').onclick = function () {
$("#f").ajaxSubmit({
target: '#yk1', //通过事件触发的提交显示在页头
});
}
</script>
</body>
</html>
在服务器端index.php内容为:
<?php
header('Content-Type: text/html; charset=UTF-8');
echo '<pre>';
print_r($_REQUEST);
echo '</pre>';
主要方法介绍:
该库扩展了jquery(在其原型和属性上添加了方法),最常使用的两个方法是(通常二选一):
$.fn.ajaxSubmit( options, data, dataType, onSuccess )
在表单对应的jquery对象上调用该方法将立即提交表单,参数如下:
options:为选项对象,通过该对象可以完整控制提交过程和结果处理,详见下文
data:为额外传递到服务器的数据,数据对象方式,非字符串方式,详见选项
dataType:为ajax请求期待的数据类型,详见选项
onSuccess:为请求成功时执行的回调
该方法也可仅接收一个回调参数,将被当做请求成功时执行的回调
$.fn.ajaxForm( options, data, dataType, onSuccess )
该方法和ajaxSubmit方法类似,参数及含义完全相同,但她不提交表单,而是为表单绑定提交事件,并设置各种AJAX参数,相当于在为表单ajax提交做准备,当表单自然提交时(派发submit事件时,通常是点击提交按钮)将采用AJAX提交,由于该方法准备的AJAX由表单自然提交触发,因此和ajaxSubmit方法相比有以下优势:
1、如果提交是由图片表单元素触发,将包含点击坐标
2、将包含提交元素(通常是提交按钮)的name/value数据
在内部,该方法绑定的ajax提交最终还是由ajaxSubmit方法执行
选项参数:
在以上两个方法的选项参数中,全部标准的jquery原生$.ajax选项可用,请查阅:
https://api.jquery.com/jQuery.ajax/
额外的或需要注意的选项如下:
beforeSerialize
表单序列化之前执行的回调函数,在取回值之前提供一个机会去操纵表单,如果返回false将阻止表单提交,回调接收两个参数:jquery包装的表单对象和选项对象
beforeSubmit
表单提交前执行的回调,如果返回false将阻止表单提交,有三个参数:数组格式的表单数据、jquery包装的表单对象和选项对象
注意:在调用顺序上,还有beforeSend、dataFilter、error 、complete等回调,由于是jquery本身支持的,这里不再列出
filtering
处理字段前调用的回调,她提供了一个机会来过滤元素,会被这样调用:els = $.map(els, filtering);,该回调有两个参数:元素和索引
clearForm
布尔值,当提交成功后,表单是否应该清理
随表单一起提交的额外数据,一个数据对象,如:data: { key1: 'value1', key2: 'value2' }
该参数仅供内部使用,是data序列化成字符串之前复制的一个复本,只用于老旧浏览器AJAX上传文件的情况,也就是表单包含<input type=’file’/>并在老旧浏览器中运行的情况,在老浏览器中文件AJAX上传需要通过<iframe>来模拟提交(见下),此时extraData会转变为<input type=’hidden’/>元素包含在表单中被一起提交,现代浏览器已经不需要这种模拟了,如果同时指定了data项和该项的情况下,该项无效。虽然该参数仅供内部使用,但有些情况下外部有特殊用途,比如在选项的发送前方法(beforeSend)中,可在该参数中设置一些值,如果服务器能收到这些值,就可说明浏览器是通过iframe模拟提交的,借此做浏览器回退处理
dataType
期望服务器返回的数据类型:null、"xml"、"script"、"json"之一,会影响到jquery的相关方法
delegation
布尔值,绑定事件时是否采用事件委托,事件委托可以将事件绑定到以后添加到页面的元素
iframe
布尔值,默认false,指示文件上传是否总是使用iframe方式,现在先进的浏览器基本使用XHR,iframe方式是一种兼容老旧浏览器的伪ajax方式,本篇下文给了一个示例
iframeTarget
字符串值(jquery选择器),当文件上传时,指定一个iframe元素作为响应目标,默认会自动创建一个临时用iframe元素,当用该项时,不会试图处理服务器返回的响应
iframeSrc
字符串值,当iframe选项被用时,指定其src属性
forceSync
布尔值,默认false,当上传文件时,是否移除传递表单前的短延迟,短延迟可以让浏览器在表单提交前执行DOM更新,比如显示一个“请稍后…”的提示,该配置项仅用于明确使用iframe配置项或不支持XHR2的浏览器上传文件时
AJAX请求使用的http方法,如:'POST', 'GET', 'PUT'
type
method选项的别名(在原生$.ajax选项中定义),当都存在时,method优先级更高
target
收到响应后更新的元素,通常是放置响应内容的元素,或被整个替换,可以是jquery选择器、jquery对象或DOM元素对象
replaceTarget
布尔值,当使用target选项时,true表示整个替换目标,false表示仅替换目标内容,默认为false
resetForm
布尔值,指示提交成功后表单是否需要重置
布尔值,指示表单提交时,值的顺序是否严格按照表单中元素的定义顺序提交,通常是按照定义顺序提交的,但如果遇到图片提交按钮(<input type=”image” />),会将图片按钮的值放到最后,该项就是针对这个另外而设置,仅在表单包含图片按钮时才有用,如果为true,那么会严格按照定义顺序提交,不会将图片按钮的值放到最后,如果为false,那么会放到最后;如果服务器对值的顺序没有要求,那么设置该项将没有什么意义
success
在成功进行AJAX时执行的回调(服务器返回响应后),接收4个参数:
data:响应数据,数据格式由dataType选项值和dataFilter回调共同决定
textStatus、jqXHR对象、jQuery 表单对象
该项已弃用,将用原生$.ajax选项中的success代替,换句话说将来将不再传递后两个参数
uploadProgress
执行上传进度的回调函数,如果浏览器支持,那么会传递以下四个参数:
event:浏览器事件
position:当前位置,整数
total:总数,整数
percentComplete:百分比,整数0-100之间
url
AJAX请求提交到的url地址
实用工具方法:
该库除ajaxForm和ajaxSubmit外,还为jquery原型添加了以下工具方法:
$.fn.formSerialize(semantic)
将表单序列化成一个查询字符串,如name1=value1&name2=value2,参数含义同semantic选项
$.fn.fieldSerialize(successful)
将匹配的字段序列化成一个查询字符串,如:
var queryString = $('#myFormId .specialFields').fieldSerialize();
先选择字段集再调用,该方法当仅仅需要表单的一部分时很有用,参数successful是一个布尔值,指示是否仅包含“成功控件successful control”,默认为true,成功控件是指能进行有效提交的控件,并非有名和值就能被提交,以下元素都不是成功控件:
1、属性disabled为真的元素
2、当表单有多个提交按钮时,没被点击的提交元素,以及重置按钮
3、没选中的复选框
4、没选中的单选按钮
5、在SELECT元素中没选中的OPTION项
6、表单编码类型不支持文件时,表单中的文件元素(仅被提交文件名)
7、没name属性等等
官网对成功控件的解释请见:
http://www.w3.org/TR/html4/interact/forms.html#successful-controls
$.fn.formToArray(semantic, elements, filtering)
将表单值转化为数组返回,返回值类似:
[ { name: 'username', value: 'jresig' }, { name: 'password', value: 'secret' } ]
参数解释:semantic、 filtering含义同配置项,elements应被传递一个数组,用于收集被收集值的表单元素,这些元素会被压入数组
$.fieldValue(el, successful)
返回一个元素的值,该方法不是定义在jquery原型上,而是作为其属性,参数含义同上
$.fn.fieldValue(successful)
返回一个数组,包含匹配的表单元素的值,参数含义同上
$.fn.resetForm()
重置表单到原始状态
$.fn.clearForm(includeHidden)
清除表单值,该方法清空text、password等能输入值的 input元素和textarea元素,重置select、radio 、 checkbox元素到未选择状态;默认不清理按钮、hidden字段的值,但可以通过参数includeHidden来改变此行为,如果参数includeHidden为true,那么将清除hidden元素的值,如果为jquery选择器字符串,那么将清除对应元素的值,如:$('#myForm').clearForm('.special:hidden')
$.fn.clearFields(includeHidden)
清除匹配表单元素的值,但仅清除表单的一部分时很有用,参数同clearForm方法
$.fn.enable(bool)
依据参数启用或禁用元素,参数为布尔值,true为启用,默认为true
$.fn.selected(select)
参数为布尔值,默认为true,针对checkbox、radio元素进行是否选中设置;也可以针对select元素中的option元素,如果select元素是单选的,那么其他option元素会被取消选择,再设置本option元素是否选中,如果是多选将不会去操作其他option元素
$.fn.attr2(attrName)
获取元素属性的值,根据jquery的版本,当没有$.fn.prop时采用$.fn.attr方法,否则使用$.fn.prop方法,但如果属性值不是字符串也不是jquery对象,那么将再次回退使用$.fn.attr方法
文件iframe方式伪ajax上传示例:
为让读者明白什么是文件iframe方式提交,这里提供一个示例,关键点在于提交表单的target属性指向一个隐藏的iframe元素,这样提交不会导致页面整个刷新,又可以从iframe元素中取回结果
前端页面如下(自行准备jquery):
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>iframe方式文件伪ajax上传</title>
<script src="jquery.min.js"></script>
</head>
<body>
选择文件立即上传:<input type="file" name="file"/><br>
上传结果:<div id="result"></div>
<script type="text/javascript">
$(function () {
// 监听文件表单change事件,有改变立即上传
$('input[name=file]').on('change', function (e) {
var $target = $(e.target);
// 创建辅助用临时iframe元素
var $frame = $('<iframe>', {name: 'upload_iframe', style: 'display: none;'});
$frame.appendTo("body");
//创建临时表单form
var $form = $('<form>', {
method: 'POST', // post方式提交
action: 'iframeUpload.php', // 文件上传的服务器地址
target: 'upload_iframe', // 将结果显示到iframe元素
enctype: 'multipart/form-data' // 二进制数据编码
});
//临时将文件表单包装到表单中
$target.wrap($form)
//提交表单
$target.parent().submit();
//获取结果 处理回调
$frame.on('load', function () {
//去除临时用包装的form
$target.parent().replaceWith($target);
var result = $frame.contents().find("body").html();
$('#result').html(result);
//移除临时iframe元素
$frame.remove();
});
});
});
</script>
</body>
</html>
服务器端iframeUpload.php代码如下:
<?php
echo '<pre>';
print_r($_FILES);
echo '</pre>';