龙空技术网

第63节 Form表单-Web前端开发之JavaScript-王唯

零点程序员 179

前言:

现在小伙伴们对“htmlvalign”大致比较关怀,姐妹们都想要剖析一些“htmlvalign”的相关资讯。那么小编也在网摘上汇集了一些对于“htmlvalign””的相关内容,希望兄弟们能喜欢,咱们一起来学习一下吧!

本内容是《Web前端开发之Javascript视频》的课件,请配合大师哥《Javascript》视频课程学习。

在HTML中,表单是用<form>元素来表示的,它与其他各种各样的表单输入元素,如<input>、<select>和<button>在客户端编程中有着重要的地位。

表单的作用是,通过表单元素收集用户的输入,再将这些输入数据提交给服务器,服务器处理接收到的数据并生成一个新的HTML页面显示在客户端;在以前,表单提交数据、服务器返回数据,此时客户端与服务端并没有其他交互行为,因此,数据提交交互性差、服务器负担重。

Javascript的最初的一个应用,就是分担服务器处理表单的任务,打破处处依赖服务器的局面;虽然现在Web和Javascript有了长足的发展,但Web表单的变化并不明显;特别是一些常见的形式,web表单并没有提供特别好的方案;最常见的操作,是使用Javascript增强了一些标准表单控件的默认行为。

表单及其控件都是HTML元素,可以使用标准的DOM技术来操作它们,另外表单已经脚本化了,也有专门的API,所以在表单编程中,最好使用表单API;

取得Form表单对象:

取得<form>元素引用的方式:最常用的方式就是将它看成与其他元素一样,使用getElementById()或getElementsByTagName()等标准的DOM技术;

var form = document.getElementById("myForm");var form = document.getElementsByTagName("form")[0];

通过document.forms集合可以取得页面中所有表单集合,在这个HTMLCollection集合中,可以通过数值索引或name或id值来取得特定的表单:

var firstForm = document.forms[0];var myForm = document.forms["myForm"];

较早的浏览器或者那些支持向后兼容的浏览器中,会把每个设置了name特性的表单作为属性保存在document对象中,如:

var form = document.myForm;

注:不推荐这种方式;

注:可以同时为表单指定id和name属性,但它们可以设置不同的值;

表单属性和方法:

表单<form>在HTML中具有action、encoding、method和target等属性,在Javascript中,它是HTMLFormElement类型,继承了HTMLElement,因而与其他HTML元素一样具有相同的默认属性,但也具有自己独有的属性和方法,其中大部分的属性都与其在HTML中的属性相对应,这些属性可以控制表单是如何来提交数据并如何显示的,如:

acceptCharset:服务器能够处理的字符集,等价于HTML中的accept-charset特性;action:接受请求的URL,等价于HTML的action特性;elements:表单中所有控件的集合(HTMLCollection);enctype:请求的编码类型(方式),等价于HTML中的enctype特性;encoding:编码,等价于HTML的encoding特性,不般不需要;length:只读,表单中控件的数量;method:请求类型(方法),等价于HTML的method特性;name:表单的名称,等价于HTML的name特性;target:用于发送请求和接收响应的窗口名称,等价于HTML的targetreset():方法,将所有表单域重置为默认值;submit():方法,提交表单;

以上的大部分属性是可写的;

<script>console.log(form.action); // demo.htmlform.action = "/login";console.log(form.action); // login// 获取表单信息function getFormInfo(){var info;var form = document.forms[0];info = "form.elements:" + form.elements + "\n";info += "form.length:" + form.length + "\n";info += "form.name:" + form.name + "\n";info += "form.acceptCharset:" + form.acceptCharset + "\n";info += "form.action:" + form.action + "\n";info += "form.enctype:" + form.enctype + "\n";info += "form.encoding:" + form.encoding + "\n";info += "form.method:" + form.method + "\n";info += "form.target:" + form.target + "\n";form.elements["txt"].value = info;}function setFormInfo(form){form.name = "yourForm"form.method = "GET";form.action = "/member";form.acceptCharset = "gb2312";form.enctype = "multipart/form-data";form.target = "_blank";var pwd = document.createElement("input");pwd.type = "password";pwd.id = "pwd";form.appendChild(pwd);}</script><form name="myForm" id="myForm" action="/login" method="POST"><p><input type="text" id="username" name="username" /></p><p><input type="button" value="表单信息" onclick="getFormInfo()" /><input type="button" value="设置表单" onclick="setFormInfo(this.form)" /></p><p><textarea id="txt"></textarea></p></form>

也可以使用DOM方法动态创建表单,如:

var form = document.createElement("form");document.body.appendChild(form);form.name = "myform";form.action = "/login";form.method = "POST";// form.submit();// 或者var btn = document.createElement("input");btn.type = "submit";btn.value = "提交";form.appendChild(btn);

Submit提交表单:

使用<input>的type特性为”submit”或”image”就可以提交表单,或者<button>也可以提交表单;

<input type="submit" value="提交" /><input type="image" src="images/submit.png" /><button type="submit">提交表单</button>

以上的按钮,只要在任何表单元素拥有焦点的情况下,按回车就可以提交表单;如果表单里没有提交按钮,按回车键不会提交表单,但有个特例,如果只有一个文本框,即使没有提交按钮,回车也会提交;

注意:textarea是个例外,如果在文本区中回车会换行,而不是提交表单;

以这种方式提交表单时,浏览器会在将请求发送给服务器之前触发onSubmit事件,利用此事件,可以验证表单数据,从决定是否允许表单提交;阻止这个事件的默认行为或返回false就可以取消表单提交,如果不阻止,就是提交表单;

var myForm = document.getElementById("myForm");myForm.addEventListener("submit", function(event){var input = document.forms[0].elements[0];if(input.value == ""){event.preventDefault();console.log("提交不了");}},false);

如果是DOM0级事件处理程序,也可以return false;

myForm.onsubmit = function(e){var input = document.forms[0].elements[0];if(input.value == ""){console.log("input不能为空");// e.preventDefault();return false; // 或者}}

如果是HTML事件处理程序,可以return false;

<form id="myForm" name="myForm" onsubmit="return validate();"><script>function validate(){var input = document.forms[0].elements[0];if(input.value == ""){console.log("input数据不能为空");return false; // 或者}return true;}</script>

submit()方法:

在Javascript中,调用submit()方法也可以提交表单;而且,这种方式不需要表单包含提交按钮,在任何时候都可以正常提交表单;

var myForm = document.getElementById("myForm");myForm.submit();

在调用submit()方法提交表单时,并不会触发onSubmit事件,因此在调用此方法之前验证表单数据;

<input id="btn" type="button" value="普通按钮" />var btn = document.getElementById("btn");// 不会触发myForm的onSubmit事件,所以数据验证必须要处理btn.addEventListener("click",function(e){if(validate()){ // 数据验证console.log("普通按钮提交");myForm.submit();}else{console.log("不能为空");}},false);

另外,调用此方法也不会触发约束验证,如:

<p>输入1-10之间的整数:<input type="number" min="1" max="10" required /></p>

所以,也需要在调用submit()方法前验证约束,如:

var num = document.querySelector('input[type="number"]');if(num.required){if(num.value == ""){console.log("num不能为空");return false;}}

有个误区,如果给一个提交按钮添加onSubmit事件,是无效的,它会直接提交,如:

<input id="mySubmit" type="submit" value="提交" onsubmit="return validate();" />

如果为一个提交按钮添加onClick事件,可以进行表单提交验证,同时也会触发表单的onSubmit事件,例如,把上例的btn的onClick事件处理程序添加到submit提交按钮,可以看以,onClick事件先于表单的onSubmit事件触发;

另外,不要为一个表单元素的name或id的值设为submit,因为它会覆盖表单的submit方法,所以当运行时,会提示不存在的submit()函数;

另外,不仅是提交按钮或普通按钮调用submit()方法能提交表单,甚至一个超链接调用submit()方法也可以提交,但要注意,需要取消超链接的默认行为:

<!-- <a href="javascript:void(0)" id="aBtn">提交</a> --><a href="#" id="aBtn">提交</a></form><script>var aBtn = document.getElementById("aBtn");aBtn.onclick = function(e){e.preventDefault(); // 或者在HTML中执行javascript:void(0)if(validate()){console.log("超链接提交");myForm.submit();}else{console.log("超链接提交数据验证不通过");}}

示例:

<!-- onsubmit="return false" 防止表单自动提交form 默认为get提交 --><form id="myForm" onsubmit="return false"><p>用户名:<input type="text" name="username" id="username" /></p><p>密码:<input type="password" name="pwd" id="pwd" /></p><p><button type="button" onclick="login()">提交</button></p></form><script>function login(){var username = document.getElementById("username").value;var pwd = document.getElementById("pwd").value;if(username != "" && pwd !=""){var myForm = document.forms["myForm"];myForm.method = "get";myForm.action = "/login";myForm.submit();}else{console.log("数据为空");}}</script>

还有一种重要的提交方式,就是Ajax提交,也就是利用XMLHttpRequest对象进行异步数据提交,它最大的特点是不会提交整个页面,只会进行局部提交。

自动提交和防止自动提交:

回车、调用提交按钮的click()方法、调用表单的submit()方法(可以在onLoad事件中,甚至可以利用setTimeout定时提交)等;

如果表单中有提交按钮,可以为表单添加onsubmit=”return false”;但此时,提交按钮也会失效;

如果表单中没有提交按钮,不会自动提交;

如果表单中只有一个文本框,但没有提交按钮,回车会自动提交,可以为表单添加onsubmit=”return false”,就不会自动提交;或者添加一个隐藏的文本框,如:

<input type="text" style="display: none;" />

也不会自动提交,注意,不是隐藏域;

或者监听文本框的onKeydown事件,如果是回车的话,不做处理,如:

<input type="text" onkeydown="if(event.keyCode==13){return false}" />

如果在表单中有提交按钮,如果表单任一个控件都处于焦点状态下,直接回车就可以提交表单,如果没有控件处于焦点状态,可以监听document的keydown事件,从而判断是否按下回车键,再进行提交,如:

document.addEventListener("keydown", function(e){if(e.keyCode == 13){document.forms[0].submit();console.log("表单提交了");}},false);

防止重复提交:

提交表单时可能出现的最大问题,就是重复提交表单;解决该问题的方法有两个:在第一次提交表单后就禁用提交按钮,或者利用onSubmit事件处理程序取消后续的表单提交操作;

禁用提交按钮:

var myForm = document.getElementById("myForm");myForm.addEventListener("submit", function(event){event.preventDefault(); // 为了能看到效果var btnSubmit = event.target.elements["btnSubmit"];btnSubmit.disabled = true;},false);

注:不能通过onclick事件处理程序来实现这个功能,原因是不同浏览器之间存在“时差”:有的会在触发表单的onSubmit事件前触发onClick事件,有些相反;对于先触发onClick事件的,意味着会在提交发生之前禁用按钮,结果永远都不会提交表单,因此最好使用onSubmit事件来禁用提交按钮;

此种方式不适合表单中不包含提交按钮的情况;

重置表单:

使用type特性为reset的<input>或<button>两种按钮可以重置表单:

<input type="reset" value="重置"><button type="reset">重置</button>

当单击重置按钮时,会触发onReset事件;利用此事件,可以在必要时取消重置操作;取消重置也就是阻止重置的默认行为,如:

var myForm = document.getElementById("myForm");myForm.addEventListener("reset", function(event){event.preventDefault();console.log("重置被禁止了");},false);

在HTML事件处理程序或DOM0级中的onReset事件中返回false也可以取消默认行为;

也可以使用Javascript调用reset()方法重置,但与调用submit()方法不同,其会触发onReset事件;

var myForm = document.getElementById("myForm");myForm.reset();//...var btn = document.getElementById("btn");btn.onclick = function(){myForm.reset(); // 会触发onReset事件};

从用户体验角度来说,重置表单并不常见,所以有可能是意外地触发了表单重置事件,所以这种需求是很少见的,更常见的做法是提供一个取消按钮,让用户能够回到前一个页面;

表单元素(控件):

可以像访问页面中的其他元素一样,使用原生DOM方法访问表单控件;

var fields = document.getElementById("username");var fields = document.getElementsByTagName("input")[0];var fields = document.querySelectorAll('#login input[type="radio"]');var fields = document.querySelectorAll('#login input[type="radio"][name="color"]');

Form表单具有length属性,其返回表单元素的数量,但是不包含<input>元素type为“image”元素;所以也可以通过访问表单的索引或属性来访问元素,如form[0]可以取得第一个表单控件或form[“color”] 或form.color获得第一个命名控件;

console.log(myForm.length);console.log(myForm[0]);console.log(myForm["username"]);console.log(myForm.username);elements:表单中所有控件的集合(HTMLCollection);var formElements = document.forms[0].elements;console.log(formElements); // HTMLFormControlsCollectionconsole.log(formElements.length); // 5

其属于HTMLFormControlsCollection集合类型,继承自HTMLCollection;这个类型没有什么特别的属性和方法;

注意,elements集合中不包括type等于image的input元素;

可以通过表单elements集合索引或name特性访问所有元素,如:

var form = document.getElementById("myForm");var field1 = form.elements[0];var field2 = form.elements["textbox1"];var fields = form.elements.color;var fieldCount = form.elements.length;

这种方式和直接利用表单的索引或name特性访问表单元素是一致的,相比之下,还是推荐使用这种方式,因为前者在未来有可能不支持,并且会引起一些歧义;

示例,所有表单元素的值不能为空,如:

<script type="text/javascript">function myCheck(){for(var i=0;i<document.forms[0].elements.length-1;i++){if(document.forms[0].elements[i].value==""){alert("当前表单不能有空项");document.forms[0].elements[i].focus();return false;}}return true;}</script><form name="myForm" method="post" action="#" onSubmit="return myCheck()">用户名:<input type="text" name="username"><br>性别:<input type="text" name="sex"><br>出生时间:<input type="text" name="birthday"><br><input type="submit" value="提交"></form>

如果有多个表单控件使用同一个name,通过elements[“name”]会返回以该name命名的一个NodeList,而通过elements[index]只会返回第一个元素;

<form id="myForm"><p><input type="radio" name="color" value="red" />red<br/><input type="radio" name="color" value="green" />red<br/><input type="radio" name="color" value="blue" />red<br/></p></form><script type="text/javascript">var myForm = document.getElementById("myForm");var colors = myForm.elements["color"];// var colors = myForm.elements.color; // 或者console.log(colors); // RadioNodeListconsole.log(colors.length); // 3var firstColor = colors[0];var firstElement = myForm.elements[0];console.log(firstColor === firstElement); // true</script>

因此,在使用索引和name特性时结果有可能是不一样的;一般来说,优先使用id属性,但是name属性在HTML表单提交中有特殊的目的,一般应用在相关的复选按钮组和强制共享name属性值的、互斥的单选按钮组;另外,对于其他表单元素来说,设置name特性的目的就是为了提交到服务端,服务端根据该name特性取得这个表单元素的值;

共有的表单控件属性:

除了<fieldset>元素外,所有表单控件都拥有相同的一组属性;由于<input>类型可以表示多种表单元素,因此有些属性只适用于某些表单元素,但还有一些属性是所有表单元素所共有的:

disabled:布尔值,表示当前控件是否被禁用;form:只读,指向当前控件所属表单的指针;如果表单元素没有包含在一个<form>中,则值为null;name:只读,当前控件的名称;readOnly:布尔值,表示当前控件是否只读;tabIndex:表示当前控件的切换(tab)序号;type:当前控件的类型,如checkbox、radio等;value:读/写,表单元素的值,也就是将被提交给服务器的值,对file来说,是只读的,包含着文件在计算机中的路径;

以上除了form属性,都可以通过Javascript动态修改,如:

var form = document.getElementById("myForm");var field = form.elements[0];field.value = "Another value";alert(field.form === form);field.focus();field.disabled = true;// 不推荐,但对input是可行的field.type="checkbox";

type属性:

除了<fieldset>之外,所有表单元素都有type属性;对于<input>元素,这个值等于HTML特性type值,如:text、password、radio、checkbox、button、file、hidden、reset、submit;对于其他元素,该值如下:

文件域:<textarea> 值为textarea单选列表:<select>…</select> 值为:select-one多选列表:<select multiple>..</select> 值为:select-multiple自定义按钮:<button>…</button> 值为:submit自定义非提交按钮:<button type=“button”>..</button> 值为button自定义重置按钮:<button type=“reset”>..</button> 值为reset自定义提交按钮:<button type=“submit”>..</button> 值为submit

此外,<input>和<button>的type属性可以动态修改,而<select>元素的type属性是只读的;示例:密码框的明文和暗文:

<style>span.icon-eye{display: inline-block; width:24px; height: 24px;background: url("images/eye.png") no-repeat; cursor: pointer;}span.icon-eye-invisible{background-position: -24px 0;}</style><p><input id="pwd" name="pwd" type="password" /><span class="icon-eye icon-eye-invisible"></span></p><script>var iconEye = document.querySelector("span.icon-eye");iconEye.addEventListener("click", function(event){var p = document.getElementsByTagName("p")[0];var pwd = document.getElementById("pwd");if(p.classList.toggle("icon-eye-invisible")){pwd.type = "text";}else{pwd.type = "password";}},false);</script>

示例:在弹出窗口提交表单

<script>function popupSend(oForm){if(oForm.method && oForm.method.toLowerCase() !== "get"){alert("只允许GET方式提交");return;}var oField, sFieldType, nFile, sSearch = "";for(var i = 0; i < oForm.elements.length; i++){oField = oForm.elements[i];if(!oField.hasAttribute("name"))continue;// sFieldType = oField.nodeName.toUpperCase() === "INPUT" ? oField.getAttribute("type").toUpperCase() : "TEXT";sFieldType = oField.nodeName.toUpperCase() === "INPUT" ? oField.type.toUpperCase() : "TEXT";if(sFieldType === "FILE"){for(nFile = 0; nFile < oField.files.length; sSearch += "&" + escape(oField.name) + "=" + escape(oField.files[nFile++].name));}else{sSearch += "&" + escape(oField.name) + "=" + escape(oField.value);}}open(oForm.action.replace(/(?:\?.*)?$/, sSearch.replace(/^&/, "?")), "submit-" + (oForm.name || Math.floor(Math.random() * 1e6)), "resizable=yes,scrollbars=yes,status=yes");}</script><form id="myForm" name="myForm" action="demo.php" method="get"><p>First Name:<input type="text" name="firstname" /><br/>Last Name:<input type="text" name="lastname" /><br/>Password:<input type="password" name="pwd"><br/>Photo:<input type="file" name="photo"><br/><input type="radio" name="sex" value="male">Male<input type="radio" name="sex" value="female">Female</p><p><input type="checkbox" name="vehicle" value="Bike">自行车<br/><input type="checkbox" name="vehicle" value="Car">汽车</p><p><input type="submit" value="提交"></p></form><script>var myForm = document.getElementById("myForm");myForm.addEventListener("submit", function(e){popupSend(this);e.preventDefault();})</script>

共有的表单控件方法:

每个表单元素都有两个方法:focus()和blur();其中,focus()方法用于获得焦点,即激活表单元素,使其可以响应键盘事件,如:

window.onload = function(e){document.forms[0].elements[0].focus();}

默认情况下,只有表单元素可以获得焦点;对于其他元素,可以设置其tabIndex设置为-1,然后再调用focus() 方法,也可以让这些元素获得焦点;

HTML5为表单控件新增了一个autofocus属性,在支持这个属性的浏览器中,只要设置这个属性,不用Javascript就能自动把焦点转移到相应的控件上,如:

<input type="text" autofocus />

如果在HTML中已经为元素设置这个属性了,就不用在Javascript中调用focus()了,因此有必要在调用focus()之前先检测是否设置了该属性,如:

window.addEventListener("load", function(event){var element = document.forms[0].elements[0];if(element.autofocus !== true){element.focus();console.log("Js focus");}});

blur()方法:从元素中移除焦点;

与focus()方法相对的是blur()方法,它的作用是从元素中移走焦点;在调用blur()时,并不会把焦点转移到某个特定的元素上,其仅仅是将焦点从调用这个方法的元素上面移走而已,如:

document.forms[0].elements[0].blur();

共有的表单元素事件:

当用户与表单元素交互时它们往往会触发鼠标、键盘或其他HTML等常规事件,除此之外,表单元素还支持以下3个事件:

blur:失去焦点时时触发;focus:获得焦点时触发;change:对于<input>和<textarea>元素,在它们失去焦点且value值改变时触发;对于<select>元素,在其选项改变时触发;

如:

var textbox = document.forms[0].elements[0];textbox.addEventListener("focus", function(event){if(event.target.style.backgroundColor != "red"){event.target.style.backgroundColor = "yellow";}});textbox.addEventListener("blur", function(event){if(/[\d]/.test(event.target.value)){event.target.style.backgroundColor = "green";}else{event.target.style.backgroundColor = "red";}console.log("blur");});textbox.addEventListener("change", function(event){if(/[\d]/.test(event.target.value)){event.target.style.backgroundColor = "green";}else{event.target.style.backgroundColor = "red";}console.log("change");});

需要强调的是,change事件对于<input>和<textarea>元素,在它们失去焦点且value值改变时触发;对于<select>元素,在其选项改变时触发,如:

var selectbox = document.forms[0].elements["mySelect"];selectbox.addEventListener("change", function(event){console.log(this.options[this.selectedIndex].value);});selectbox.addEventListener("blur", function(e){console.log("select blur");});

当改变选项时,会触发change事件,但此时,<select>仍处于焦点状态,当其失去焦点时,才会触发blur事件,这一点,有<input>有很大区别;

事件处理程序中的this:

事件处理程序中的this是触发该事件的元素的一个引用;例如,可以通过this.form来取得其所在的Form对象的引用;通过this.form.x来获取该表单中其它的表单元素;

textbox.addEventListener("focus", function(event){console.log(this);console.log(this === event.target); // trueconsole.log(this.form);console.log(this.form.elements["city"]);});

标签: #htmlvalign