zoukankan      html  css  js  c++  java
  • JS-中对表单处理


    一、表单的基本介绍

    1、

    HTML 中,表单是由<form>元素来表示的,而在 JavaScript 中,表单对应的则是HTMLFormElement 类型。 HTMLFormElement 继承了 HTMLElement, 因此它拥有 HTML 元素具有的默认属性,并且还独有自己的属性和方法:

    HTMLFormElement 属性和方法
    属性或方法  说明
    acceptCharset  服务器能够处理的字符集
    action  接受请求的 URL
    elements  表单中所有控件的集合
    enctype  请求的编码类型
    length  表单中控件的数量
    name  表单的名称
    target  用于发送请求和接受响应的窗口名称
    reset()  将所有表单重置
    submit()  提交表单





    表单的获取可以通过传统的DOM来获取也可以通过HTML DOM 中提供的方法来获取:var fm=document.forms[0] / var fm = document.forms["myForm"];

    2、通过submit按钮提交表单

    表单的提交可以通过提交按钮submit来实现,但是一般都不通过这种按钮来提交表单,如果页面中有这个按钮,可以再表单的提交事件中取消掉默认的提交:

    <span style="font-size:18px;">下面代码段中出现的addEvent方法和preDef方法,见《DOM中事件绑定补充方法》<span style="font-family: 'Microsoft YaHei'; line-height: 30px;"> 一文中</span></span>
    <span style="font-size:18px;">	//通过表单的submit事件中来阻止默认的submit按钮点击的提交
    	addEvent(fm,"submit",function(evt){
    		preDef(evt);
    	})
    
      //input中的submit按钮的submit事件是不能够阻止表单提交的
    	var sub = document.getElementById("subOne");
    	addEvent(sub,"submit",function(evt){	
    		preDef(evt);
    	})
    
      //但是在submit按钮的click事件中是可以阻止表单的提交的
    	var sub = document.getElementById("subOne");
    	addEvent(sub,"click",function(evt){
    		preDef(evt);
    	})
    
      //打印后提交
      	var fm = document.forms["oneForm"];
    	addEvent(fm,"submit",function(evt){
    		alert("OK");
    	})
    
      //不会打印,直接提交,提交是因为触发了表单的submit事件
    	var sub = document.getElementById("subOne");
    	addEvent(sub,"submit",function(evt){
    		alert("OK");
    	})</span>

    出现上面的几种情况是因为,把submit事件注册到input中的submit按钮上面,是无法出发表单的submit事件的,必须把submit事件注册到form表单上面,才能够触发表单的submit提交事件,只不过因为表单是看不见的,触发submit事件的流程是点击input中的submit按钮而已。故需要将submit事件注册到表单上面

    3、通过submit()方法来提交表单

    其实在日常的表单应用中,提交表单更加常用的方法是通过表单中提供的一个方法:submit()方法,通过这个方法我们可以再任意的地方,通过各种事件或者条件去提交表单,可以把提交事件写在普通的按钮上,也可以写在一个strong标签上。

    <span style="font-size:18px;">  //使用表单的 submit()方法来让非submit按钮实现表单的提交
    	var box =document.getElementById("btnOne");
    		var fm = document.forms["oneForm"];
    		addEvent(box,"click",function(evt){
    			alert("OK");
    			fm.submit();
    	})
      
      //通过fm.submit()让strong标签也能够实现表单的提交
    	var str = document.getElementById("strong");
    		var fm = document.forms["one"];
    		addEvent(str,"click",function(evt){
    			fm.submit();
    	})
    
      //按下ctrl加回车键也能够实现提交
    	var fm = document.forms["one"];
    	addEvent(fm,"submit",function(evt){
    		//阻止提交
    		preDef(evt);
    	})
    	//按下ctrl加回车键也能够实现提交
    	addEvent(document,"keydown",function(evt){
    		var e = evt || window.event;
    		if(e.ctrlKey && e.keyCode == 13){
    			fm.submit();
    		}
    	})
    
    //PS:在表单中尽量避免使用 name="submit"或 id="submit"等命名,这会和 submit()方法发生冲突导致无法提交。</span>

    4、重复提交的处理

    提交数据最大的问题就是重复提交表单。 因为各种原因, 当一条数据提交到服务器的时候会出现延迟等长时间没反映, 导致用户不停的点击提交, 从而使得重复提交了很多相同的请求,或造成错误、或写入数据库多条相同信息。我们可以先通过程序来模拟延时提交:

    <span style="font-size:18px;">  //模拟延时提交表单	
    	var fm =document.forms["one"];
    	addEvent(fm,"submit",function(evt){
    		preDef(evt);
    		//
    		setTimeout(function(){
    			fm.submit();
    		},3000);
    	})</span>

    对于重复提交的解决办法有两种:一是在提交之后将提交按钮给禁用掉,但是这有一个问题当用户点击F5重新刷新页面的时候,这个提交按钮还是被禁用的,因为刷新的是内存里面缓存的HTML页面;第二中方法就是做一个标志位,在提交之后将这个标志位进行一个赋值,然后当用户再次提价的时候,就先判断这个标识位的值

    <span style="font-size:18px;">  //解决办法之一,第一次提交之后将提价按钮给禁用掉,但是这种通过浅层刷新后还是禁止的,这种不好
    	  var fm =document.forms["one"];
    		addEvent(fm,"submit",function(evt){
    			preDef(evt);
    			//这种方法只是能够防止重复点击提交按钮而发生的提交
    			document.getElementById('subOne').disabled = true;	//第一次提交后,将提交按钮禁止
    			setTimeout(function(){
    				fm.submit();
    			},3000);
    		})
      
      //解决办法二,做一个标志位
      	var fm =document.forms["one"];
    	var flag = false;		//在第一次提交之后做一个标记,让它为true,在下次提交之前先判读
    	addEvent(fm,"submit",function(evt){
    		preDef(evt);
    		addEvent()
    		document.getElementById('subOne').disabled = true;	//第一次提交后,将提交按钮禁止
    		if(flag == true){	//表示我提交过一次
    			return;
    		}
    		flag = true;	
    		setTimeout(function(){
    			fm.submit();
    		},3000);
    	})</span>


    5、重置表单

    表单中有一个按钮type="reset",当点击这个按钮的时候,用户在本表单中填充的所有的信息都将被清空,故体验不好。

    也可以通过表单中的方法 fm.reser() 来重置表单,使用方法和提交表单是一样的,可以再任何地方进行调用。

    6、表单字段

     form里面的input、submit、textarea select 这些叫做表单控件,其实就是表单元素标签。

    可以通过fm.elements[0] 或者fm.elements["name"]等方式来获取表单控件,当然也可以通过DOM中的方法来获取表单字段,但是很不方便,前面这种方法中,获取的时候只是会获取表单字段,如果非表弟那字段这会被忽略掉,并且想radio这种多个控件使用同一个名称,然后利用名称来获取的时候,会返回一个NodeList集合。

    表单字段有一些共有的属性和方法:这些属性可读也可写,同时type属性可以修改控件的类型,但最好不要这样做,

    共有的表单字段属性

    属性 说明
    disabled  布尔值,表示当前字段是否被禁用
    form  指向当前字段所属表单的指针,只读
    name  当前字段的名称
    readOnly  布尔值,表示当前字段是否只读
    tabIndex  表示当前字段的切换
    type  当前字段的类型
    value  当前字段的值





    每一个表单字段都有两个方法:focus() 、blur() 分别表示将焦点移动到表单字段元素里和将焦点移除表单字段

    每一个表单字段还有三个事件:

    事件名  说明
    blur  当字段失去焦点时触发
    change 对于<input>和<textarea>元素,在改变 value 并失去焦点;触发;对于<select>元素,在改变选项时触发
    focus  当前字段获取焦点时触发






    二、文本框脚本

    1.文本框的基本属性

    在 HTML 中,有两种方式来表现文本框:一种是单行文本框<input type="text">,一种是多行文本框<textarea>。虽然<input>在字面上有 value 值,而<textarea>却没有,但通过都可以通过 value 获取他们的值。

    <span style="font-size:18px;"><span style="white-space:pre">	</span>var fm = document.forms[0];
    	var textOne = fm.elements["textOne"];	//单行的文本框input
    	var textMul = fm.elements["textMultiple"];	//多行的文本框 textarea
    	<span style="font-family:SimSun;">alert(textOne.value+"__"+textArea.value);	//推荐用这种方法,因为文本值改变不一定会反应到DOM中
    	alert(textMul.getAttribute("value"));	//null	高版本的浏览器
    	alert(textMul.innerHTML);
    	alert(textOne.getAttribute("value"));	//获取的是属性的值
    	alert(textMul.getAttribute("value"));	//兼容性会有问题,IE8可以获取,非IE获取不到
    
      //defaultValue  获取默认值,最开始的值,无论文本框中的值怎么改变,这个属性获得的值是不变的
    	alert(textMul.defaultValue);	//用来获取文本框最初的值,也就是最开始的value值
    	alert(textOne.defaultValue);</span></span>

    文本框中有一个方法:select() 可以选中当前文本框中所有的文本内容,当它和 focus() 方法一起使用的时候,就可以讲当前文本内容全选并且具有焦点

    <span style="font-size:18px;">textOne.select();
    textOne.focus();</span>


    2、选择部分文本

    文本的选择中,火狐和IE提供的方式是不一样的,但是火狐提供的方法在IE9+以上已经完全支持,当然也同时支持自家提供的在IE8中的方法。兼容方法如下

    <span style="font-size:18px;">	function selectText(obj,start,end){		//对象,起始索引,结束索引
    		//获取提供了一个方法,传递两个参数,起始索引和结束索引
    		if(typeof obj.setSelectionRange == "function"){
    			obj.setSelectionRange(start,end);
    			obj.focus();
    		}else if(obj.createTextRange){	//IE8是通过文本范围来选择的
    			var range = obj.createTextRange();	//创建一个文本范围
    			range.collapse(true);				//将指针移动到起点
    			range.moveStart("character",start);	//character表示逐字阅读,start起点
    			range.moveEnd("character",end-start);//第二个参数代表的是要选择的文本长度,故两索引相减
    			range.select();
    		}
    	}</span>


    3、获取选择的文本

    在select事件中,其它浏览器都是松开鼠标后才触发,但是IE8是只要一选择字符就立即触发

    获取选择的文本中,火狐提供了两个属性,分别是选择的文本的起始和结束索引,IE8也提供了一个select对象,这个对象是document的,但是IE11中已经不支持通过这种方式来获得选择的文本。兼容方法如下:

    <span style="font-size:18px;">	function getSelect(obj){
    		if(typeof obj.selectionStart == "number"){	//火狐中判断起始索引是否是number类型
    			//通过截取字符串来完成对选择的文本就获取
    			return obj.value.substring(obj.selectionStart,obj.selectionEnd);
    		}else if(document.selection){			//IE8,这个select对象中保存了document中所有的选择信息
    			return document.selection.createRange().text;
    		}
    	}
    	//document.selection对象可以选择
    	//document.selection有一个方法可以创建文本范围对象:createRange();
    	//createRange()有一个属性是text,可以得到你选择的文本</span>


    4、阻止默认输入

    很多时候我们希望只是允许用户输入少数的几个键,比如只能够输入数字键,就需要对用户输入的键进行一个判断。

    <span style="font-size:18px;">  //只是运行数字输入,但是火狐中退格键,删除键,左右键等非字符键也会被阻止,但是他们的编码都是0,Safari中编码则是8
    	addEvent(txtMul,"keypress",function(evt){
    		var e = evt ||window.event;
    		var keyCod = getCharCode(evt);	//getCharCode(evt)返回的是按键的编码,是一个自己写的兼容方法
    		//通过正则表达式来进行匹配,String.formCharCode()方法能够将编码转换成对应的字符
    		if(!/d/.test(String.fromCharCode(keyCod)) && keyCod > 0){	//若要兼容Safari将0改为8即可
    			preDef(evt);
    		}
    	})
    //PS:charCode > N,N只限于放开光标键退格键和删除键,放的太多就会有更多的键被释放</span>


    上面的方法中只是能够阻止用户通过键盘的输入,但是不能够阻止通过复制剪切和粘贴等方式来输入,要阻止这些就通过相应的事件中阻止

    <span style="font-size:18px;">	//阻止对文本框的拷贝,粘贴和剪切操作
    	addEvent(txtMul,"cut",function(evt){
    		preDef(evt);
    	})
    	addEvent(txtMul,"copy",function(evt){
    		preDef(evt);
    	});
    	addEvent(txtMul,"paste",function(evt){
    		preDef(evt);</span>


    中文输入法的禁止:中文输入法, 它的原理是在输入法面板上先存储文本, 按下回车就写入英文文本, 按下空格就写入中文文本。可以通过CSS来禁止也可以通过JS来禁止,但是禁止输入这样的体验不好,用户还以为是自己的电脑出现了一定的问题。而且谷歌还不支持这两种写法,最好的方法是进行文本的替换,将不允许输入的替换成空字符

    <span style="font-size:18px;">//屏蔽中文输入法的问题,最好的办法是将字符进行一个替换
    	style="ime-mode:disabled"	//CSS直接编写,谷歌不支持
    
    	txtOne.style.imeMode ='disabled';	//在JS中设置,谷歌不支持
    
    	addEvent(txtOne,"keyup",function(evt){<span style="white-space:pre">		</span>//都支持
    		this.value = this.value.replace(/[^d]/g,'');
    	})</span>


    5、自动切换焦点

    在文本框的输入中,有时文本框只是运行用户输入固定长度的字符,比如在输入银行的卡号的时候,最多只是能够输入19位,这时可以通过文本框的属性来设置最大输入的长度:maxlength = 19;

    所谓的自动切换焦点就是,当用户在第一个文本框中输入完成最大允许输入的长度后,当用户输入下一个字符的时候将焦点自动切换到表单中的下一个控件上去,当然这都需要控件设置最大输入长度。实现方法如下:

    <span style="font-size:18px;">	addEvent(fm.elements["txt1"],"keyup",tabFocus);
    	addEvent(fm.elements["txt2"],"keyup",tabFocus);
    	addEvent(fm.elements["txt3"],"keyup",tabFocus);
    
    	function tabFocus(evt){
    		var e = evt || window.event;
    		//先判断当前的文本框中具有的长度和最大长度的关系
    		if(this.value.length == this.maxLength){
    			//遍历所有的控件
    			for(var i=0; i<fm.elemets.length; i++){
    				//如果当前是当前控件,就让下一个控件获得焦点
    				if(fm.elements[i]==this){
    					fm.elements[i+1].focus();
    				}
    			}
    		}
    	}</span>

    上面的方法中要注意:this的传递问题,特别是IE8中不能够自动传递this,故在addEvent()方法中最后要通过冒充调用将this传递过去。如果不传递this,可以通过下面的方法先获取时间源,然后再通过事件源来操作。

    <span style="font-size:18px;">function tabFocus(evt){
    		var e = evt || window.event;
    		//先获取事件源
    		var target = getElement(e);
    		if(target.value.length == target.maxLength){
    			//遍历所有的控件
    			for(var i=0; i<fm.elements.length; i++){
    				//如果是当前控件,就让下一个控件获得焦点
    				if(fm.elements[i] == target){
    					fm.elements[i+1].focus();
    				}
    			}
    		}
    	}</span>



    三、选择框脚本

    1、select的一些属性和方法

    选择框脚本主要是针对表单中的 select 标签,它有一些属性和方法能够方便的操作这个标签,属性就不列举了,在代码中都有,HTML中有一个name="city"的select标签

    <span style="font-size:18px;">var fm = document.forms[0];
    	var city = fm.elements["city"];
    	alert(city);	//object HTMLSelectElement]
    
    	//允许选择多行
    	city.multiple = true;
    	//选择框中可见的行数
    	city.size = 5;
    
    	//<option>元素的 HTMLColletion 集合
    	var option = city.options;
    	alert(option);	//object HTMLOptionsCollection	IE11:HTMLSelectElement
    
    	//基于 0 的选中项的索引,如果没有选中项,则值为-1
    	city.selectedIndex = 2;	
    	alert(city.selectedIndex);
    
    	//增加一个最新的选项,IE11 火狐支持,谷歌是添加到最后
    	var op = document.createElement("option");
    	op.innerHTML = "hh";
    	city.add(op,2)
    
    	//移除给定索引的选项
    	city.remove(2);
    
    	//单选就返回select-one	多选就是 select-multiple
    	alert(city.type);	//select-one
    PS:选择框里的 type 属性有可能是:select-one,也有可能是:select-multiple,这取决于 HTML 代码中有没有 multiple 属性。
    </span>


    2、option 选项的一些属性和方法:

    <span style="font-size:18px;">	alert(city.options[2]);		//object HTMLOptionElement
    	alert(city.options[2].index);	//获取当前option的索引
    
    	//当前选项是否被选中
    	alert(city.options[2].selected);
    
    	//当前选择项的文本
    	alert(city.options[0].text);
    	alert(city.options[0].firstChild.nodeValue);	//不推荐
    
    	//当前选择项的标签
    	alert(city.options[0].label);
    
    	//获取当前选择项的值
    	alert(city.options[0].value);	//推荐
    	alert(city.options[0].getAttribute("value"))	//不推荐
      //PS:当选项没有 value 值的时候,IE8 会返回空字符串,其他浏览器以及高版本的IE会返回 text 值
    	alert(city.options[4].value);
    
    	//这个定位必须在select上
    	city.selectedIndex = 2;
    
    	//这个选项的定位必须在option上
    	city.options[2].selected = true;</span>


    选择项改变事件:change 必须是定位在select标签上而不是定位在option标签上。

    给select标签添加选项:

    DOM添加和构造函数方法添加

    <span style="font-size:18px;">//添加选项	通过DOM和option构造函数两种方式添加
    	//DOM添加都是添加到最后
    	var op = document.createElement("option");
    	op.appendChild(document.createTextNode("新添加"));
    	op.setAttribute("value","newAdd");
    	city.appendChild(op);
    	
    	//通过option构造函数来创建
    	var op = new Option("newAdd","新添加");
    	city.appendChild(op);	//IE8会出现一个bug
    
    	//通过add添加,参数一是text,参数二是value
    	var op = new Option("newAdd","新添加");
    	city.add(op,2);	//第二个参数添加的索引,但是谷歌添加到最后,
    	city.add(op,null);
    	city.add(op,undefined);	//这两中都是添加到最后
    
    PS:在 DOM 规定,add()中两个参数是必须的,如果不确定索引,那么第二个参数设置 null 即可,即默认移入最后一个选项。但这是 IE 中规定第二个参数是可选的,所以设置null 表示放入不存在的位置,导致失踪,为了兼容性,我们传递 undefined 即可兼容。
    </span>


    移除select标签中的选项:

    DOM 方法移除,HTML DOM方法移除, 赋值为 null 移除

    <span style="font-size:18px;">	//移除选项,当移除后,下面的选项会向上顶,故移除第一个就可以移除全部
    	//city.removeChild(city.options[1]);	//DOM移除
    	//city.remove(2)		//remove()方法移除	推荐
    	city.options[3]=null;	//null移除</span>


    移动选项

    如果有两个选择框, 把第一个选择框里的第一项移到第二个选择框里, 并且第一个选择框里的第一项被移除。

    <span style="font-size:18px;">	var city = fm.elements["city"];
    	var none = fm.elements["none"];	//页面上的select标签名称
    	addEvent(city,"click",function(){
    		//先获得点击的选项的索引值,然后再获得选项
    		none.appendChild(this.options[this.selectedIndex]);	//移动,并自我删除
    	})</span>


    排序操作:

    <span style="font-size:18px;">var op = city.options[2];//获得索引为2的选项
    	//将op插入到它前面一个选项的前面,也就是op和前面一个选项进行了一个交换
    	city.insertBefore(op,city.options[op.index-1]);
    </span>


    单选按钮和复选按钮的获取

    <span style="font-size:18px;">//单选按钮
    	for(var i=0;i<fm.elements["sex"].length;i++){
    		if(fm.sex[i].checked == true){
    			alert(fm.sex[i].value);
    		}
    		//defaultChecked 属性,它获取的是原本的 checked 按钮对象,而不会因为 checked 的改变而改变
    		if(fm.sex[i].defaultChecked == true){
    			alert(fm.sex[i].value)
    		}	
    	}
    
    //复选按钮	同样有默认选择属性 defaultChecked
    	var love="";
    		for(var i=0;i<fm.gender.length;i++){
    			if(fm.gender[i].checked == true){
    				love+=fm.gender[i].value;
    			}
    			if(fm.gender[i].defaultChecked == true){
    				alert(fm.gender[i].value);
    			}
    		}
    	alert(love)</span>



    <pre><pre code_snippet_id="326713" snippet_file_name="blog_20140504_10_8629595" name="code" class="javascript"><pre>
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
  • 相关阅读:
    内核模式之事件
    用户模式之临界区
    _stdcall与_cdecl区别
    列出系统所有进程
    一道多线程的题
    进程间通信三:父进程传参数与子进程返回值
    进程间通信二:管道技术之命名管道
    进程间通信二:管道技术之匿名管道
    进程间通信二:管道技术之输入输出重定向
    补充实验1:dhcp服务器分配网关-路由器的静态路由优先级
  • 原文地址:https://www.cnblogs.com/qigang/p/3841948.html
Copyright © 2011-2022 走看看