处理表单
学习要点:
1.表单介绍
2.文本框脚本
3.选择框脚本
为了分担服务器处理表单的压力,JavaScript提供了一些解决方案,从而大大打破了处理依赖服务器的局面。
一、表单介绍
在HTML中,表单是由<form>元素来表示的,而在JavaScript中,表单对应的则是HTMLFormElement类型。
HTMLFormElement继承了HTMLElement,因此它拥有HTML元素具有的默认属性,并且还独有自己的属性和方法。
HTMLFormElement属性和方法
属性和方法
说明
acceptCharset
服务器能够处理的字符集
action
接受请求的URL
elements
表单中所有控件的集合
enctype
请求的编码类型
length
表单中控件的数量
name
表单的名称
target
用于发送请求和接受响应的窗口名称
reset()
将所有表单重置
submit()
提交表单
获取表单<form>对象的方法有很多种,如下:
document.getElementById('myform');
document.getElementsByTagName('form')[0];
document.forms[0];
document.forms['youForm'];
document.querySelector('form');
document.querySelectorAll('form')[0];
document.youForm;
<form id="myform" name="youForm">
姓名:<input type="text" name="user">
<input type="submit" value="提交">
</form>
//js代码
addEvent(window , 'load' , function(){
var fm = document.getElementById('myform');
});
PS:最后一种方法使用name名称直接获取元素,已经不推荐使用,这是向下兼容的最早期用法。问题颇多,比如
有两个相同名称的,变成数组;而且这种方式以后有可能会不兼容。
提交表单
通过事件对象,可以阻止submit的默认行为,submit事件的默认行为就是携带数据跳转到指定页面。
addEvent(fm , 'submit' , function(evt){
preDef(evt);
});
我们可以使用submit()方法来自定义触发submit事件,也就是说,并不一定非要点击submit按钮才能提交。
if(e.ctrlKey && e.keyCode == 13) fm.submit();
//判断按住了ctrl和enter键触发
<form id="myform" name="youForm">
姓名:<input type="text" name="user">
<input id="button" type="button" value="我其实是不能提交的">
<input id="sub" type="submit" value="提交">
<strong>我也可以实现提交</strong>
</form>
//js代码
addEvent(window , 'load' , function(){
var fm = document.getElementById('myform');
//阻止提交
addEvent(fm , 'submit' , function(evt){
preDef(evt);
});
var button = document.getElementById('button');
addEvent(button , 'click' , function(evt){
fm.submit(); //可以让非submit按钮提交表单
});
var strong = document.getElementsByTagName('strong')[0];
addEvent(strong , 'click' , function(){
fm.submit();
});
//实现ctrl+enter实现提交
addEvent(document , 'keydown' , function(evt){
var e = evt || window.event;
if(e.ctrlKey && e.keyCode == 13) fm.submit();
});
//使用fm.submit()可以让非submit按钮提交表单
//PS:submit事件,用传统的方式,fm.onsubmit = function(){};
//疑问:submit为什么要用form对象触发呢?为什么不能是inout中的submit按钮触发呢?
//var sub = document.getElementById('sub');
//alert(sub);
//addEvent(sub , 'submit' ,function(evt){
// preDef(evt);
//});
//PS:把submit事件注册到input中的submit按钮,是无法触发submit事件的
//PS:必须把submit事件绑定到form对象上,才可以触发submit事件
//PS:只不过触发submit事件的流程是点击input中的submit按钮而已
//addEvent(sub , 'click' ,function(evt){
// alert('journey');
//});
});
function addEvent(obj , type , fn){
//添加事件兼容
if(obj.addEventListener){
obj.addEventListener(type,fn);
}else if(obj.attachEvent){
obj.attachEvent('on' + type , fn);
}
}
function removeEvent(obj , type , fn){ //移除事件兼容
if(obj.removeEventListener){
obj.removeEventListener(type , fn);
}else if(obj.detachEvent){
obj.detachEvent('on' + type , fn);
}
}
function getTarget(evt){ //得到事件目标
if(evt.target){
return evt.target;
}else if(window.event.srcElement){
return window.event.srcElement;
}
}
function preDef(evt){ //跨浏览器动态阻止事件行为
var e = evt || window.event;
if(e.preventDefault){
e.preventDefault();
}else{
e.returnValue = false;
}
}
PS:在表单中尽量避免使用name="submit"或id="submit"等命名,这会和submit()方法发生冲突导致无法提交。
提交数据最大的问题就是重复提交表单。因为各种原因,当一条数据提交到服务器的时候会出现延迟等长事件没有
反应,导致用户不停的点击提交,从而使得重复提交了很多相同的请求,或造成错误、或写入数据库多条相同信息。
addEvent(fm , 'submit' , function(evt){
//模拟延迟
preDef(evt);
setTimeout(function(){
fm.submit();
}, 3000);
});
有两种方法可以解决这种问题:第一种就是提交之后,立刻禁用点击按钮;第二种就是提交之后取消后续的表单提交
操作。
方法一:
addEvent(fm , 'submit' , function(evt){
//模拟延迟
preDef(evt);
document.getElementById('sub').disbled = true; //将按钮禁用,这种方法只限于提交按钮防止重复提交
setTimeout(function(){
fm.submit();
}, 3000);
});
方法二:
var flag = false;
//设置一个监听变量
addEvent(fm , 'submit' , function(evt){
//模拟延迟
preDef(evt);
if(flag == true) return //如果存在返回 退出事件
flag = true; //否则确定是第一次,设置为true
setTimeout(function(){
fm.submit();
}, 3000);
});
PS:在某些浏览器,F5只能起到缓存刷新的效果,有可能获取不到真正的源头更新的数据,那么使用ctrl+F5就可以把源头
给刷出来。
重置表单
用户点击重置按钮时,表单会被初始化。虽然这个按钮还得以保留,但目前的Web已经很少去使用了。因为用户已经
填写好各种数据,一不小心点了重置就会全部清空,用户体验极差。
有两种方法调用reset事件,第一就是直接type="reset"即可;第二种就是使用fm.reset()方法调用即可。
<input type="reset" value="重置" />
//不使用JS代码实现重置
addEvent(document , 'click' , function(evt){
//使用fm.reset()方法调用
fm.reset();
});
addEvent(window, 'load' , function(){
var fm = document.getElementById('myform');
//reset事件,reset()方法
addEvent(fm , 'reset' , function(){ //必须点击reset按钮才能执行
fm.reset();
});
addEvent(document , 'click' , function(evt){
fm.reset();
});
});
表单字段
如何访问表单元素,可以使用之前章节降到的DOM方法访问。但使用原生的DOM访问虽然比较通用,但不是很
便利,表单处理中,我们建议使用HTMLDOM,它有自己的elements属性,该属相是表单中所有元素的集合。
表单控件是什么?form里面的input 、 submit 、 textarea 、 select这些就是表单控件,其实就是元素标签
fm.elements[0];
//获取第一个表单字段元素
fm.elements['user'];
//获取name是user的表单字段元素
fm.elements.length;
//获取所有表单字段的数量
如果多个表单字段都是用同一个name,那么就会返回该name的NodeList表单列表。
fm.elements['sex'];
//获取相同name表单字段列表
addEvent(window , 'load' , function(){
var fm = document.getElementById('myform');
var sexList = fm.elements['sex'];
alert(sexList[0]);
alert(sexList[0].value);
alert(sexList[0].name);
alert(sexList[1].disable = true);
});
PS:我们是通过fm.elements[0]来获取第一个表单字段的,但页可以使用fm[0]直接访问第一个字段。因为fm[0]
访问方式是为了向下兼容的,所以建议使用elements属性来获取。
公有表单字段属性
除了<fieldset>元素之外,所有表单字段都拥有相同的一组属性。由于<input>类型可以表示多种表单字段,因此
有些属性只适用于某些字段,以下罗列出共有属性:
属性和方法
说明
disable
布尔值,表示当前字段是否被禁用
form
只想当前字段所属表单的指针,只读
name
当前字段的名称
readOnly
布尔值,表示当前字段是否只读
除了<fieldset>字段之外,所有表单字段都有type属性,对于<input>元素,这个值等于HTML属性的type值,对于
非<input>元素,这个type的属性值如下:
元素说明
HTML标签 type属性值
单选列表
<select>...</select> select-one
多选列表
<select multiple>...</select> select-multiple
自定义按钮
<button>...</button> button
自定义非提交按钮
<button type="button">...</button> button
自定义重置按钮
<button type="reset">...</button> reset
自定义提交按钮
<button type="submit">...</button> submit
PS:<input>和<button>元素的type属性是可以动态修改的,而<select>元素的type属性则是只读的。(在不
必要的情况下,建议不要修改type)。
共有的表单字段方法
每个表单字段都有两个方法:foucs()和blur()。
方法
说明
foucs()
将焦点定位到表单字段里
blur()
从元素中将焦点移走
fm.elements[0].foucs();
//将焦点移走
fm.elements[0].blur();
//将焦点移出
共有的表达字段事件
表单共有的字段事件有以下三种:
事件名
说明
blur
当字段失去焦点时触发
change
对于<input>和<textarea>元素,在改变value并失去焦点时触发;对于
<select>元素,在改变选项时触发
focus
当前字段获取焦点时触发
addEvent(textField , 'foucs' , function(){
//缓存blur和change再测试一下
alert('journey');
});
PS:关于blur和change事件的关系,并没有严格的规定。在某些浏览器中,blur事件会先与change事件发生;
而其他浏览器中,则恰好相反。
二、文本框脚本
在HTML中,有两种方式来表现文本框:一种是单行文本框<input type="text">,一种是多行文本框<textarea>。
虽然<input>在字面上有value值,而<textarea>却没有,但都可以通过value获取它们的值。
var textField = fm.elements[0];
var areaField = fm.elements[1];
alert(textField.value + '.' + areaField.value);
PS:使用表单的value是最推荐使用的,它是HTMLDOM中的属性,不建议使用标准DOM的方法。也就是说不要
使用getAttribute()获取value值。原因很简单,对value属性的修改,不一定会反应在DOM中,
除了value值,还有一个属性对应的是defaultValue,可以得到原本的value值,不会因为值的改变而改变。
alert(textField.defaultValue);
//得到最初的value值
选择文本
使用select()方法,可以将文本框里的文本选中,并且将焦点设置到文本框中。
textField.select();
//选中文本框中的文本
选择部分文本
在使用文本框内容的时候,我们又是要直接选定部分文本,这个行为还没有标准。Firefox的解决方案是:setSelectionRange()方法。
这个方法接受两个参数:索引和长度。
textField.setSelectionRange(0,1);
//选择第一个字符串
textField.focus();
//焦点移入
textField.setSelectionRange(0,textField.value.length);
//选择全部
textField.foucs();
//焦点移入
除了IE,其他浏览器都支持这种写法(IE9+支持),那么IE想要选择部分文本,可以使用IE的范围操作。
var range = textField.createTextRange();
//创建一个文本范围对象
range.collapse(true);
//将指针移到起点
range.moveStart('character' , 0);
//移动起点,character表示逐字移动
range.moveEnd('character' , 1);
//移动终点,同上
range.select();
//焦点选定
PS:关于IE范围的详细讲解,我们将在今后的课程中继续讨论。并且W3C也有自己的范围。
//选择部分文本实现跨浏览器兼容
function selectText(text , start , top){
if(text.setSelectionRange){
text.setSelectionRange(start , stop);
text.foucs();
}else if(text.createTextRange){
var range = text.createTextRange();
range.collapse(true);
range.moveStart('character' , start);
range.moveEnd('character' , stop-start); //用终点减去起点位置
range.select();
}
}
使用select事件,可以选中文本框文本后触发。
addEvent(textField , 'select' , function(){
alert(this.value); //IE事件需要传递this才可以这么写
});
取得选择的文本
如果我们想要取得选择的那个文本,就必须使用一些手段。目前位置,没有任何规范解决这个问题。Firefox为文本
框提供了两个属性:selectionStart和selectionEnd。
addEvent(textField , 'select' , function(){
alert(this.value.substring(this.selectionStart , this.selectionEnd));
});
除了IE,其他浏览器均支持这两个属性(IE9+已支持)。IE不支持,而提供了另一个方案:selection对象,属于
document。这个对象保存着用户在整个文档范围内选择的文本信息。导致我们需要做浏览器兼容。
function getSelectText(text){
if(typeof text.selectionStart == 'number'){ //非IE
return text.value.substring(text.selectionStart , text.selectionEnd);
}else if(document.selection){ //IE
return document.selection.createTextRange().text;//获取IE选择的文本
}
}
PS:有一个最大的问题,就是IE在触发select事件的时候,在选择一个字符后立即触发,而其他浏览器是选择想要的
字符释放鼠标后才触发。所以,如果使用alert()的话,导致跨浏览器的不兼容,我们没有办法让浏览器行为保持统一,
但可以通过不去使用alert()来解决。