第十四章:表单脚本(选择框脚本、表单序列化、富文本编辑)

xiaoxiao2021-02-28  77

表单脚本

选择框脚本

选择框是通过<select>和<option>元素创建的。<select>元素是在JS中是HTMLSelectElement 类型,提供了额外的属性和方法: add(newOption, relOption):向控件中插入新<option>元素,其位置在相关项(relOption)之前。可以通过new Option(text, value)创建HTMLOptionElement 类型的对象,此外用这个函数来调换两个option元素位置也挺好用的(类似于insertBefore)。multiple:布尔值,表示是否允许多项选择;等价于HTML 中的multiple 特性。options:控件中所有<option>元素的HTMLCollection。remove(index):移除给定位置的选项。如果不传参数,则会把整个select移除掉。如果传的不是Number类型的,会通过valueOf或者toString转成Number类型。没有重写的话会返回0?selectedIndex:基于0 的选中项的索引,如果没有选中项,则值为-1。对于支持多选的控件,只保存选中项中第一项的索引。改变这个值也可以设置选中项。size:选择框中可见的行数;等价于HTML 中的size 特性。type:”select-one“或”select-multiple“,取决是是否有multiple 特性。选择框的value属性由选中项决定(一些自定义标签实现了设置value改变选中项的功能,但默认是没有这个功能的): 如果没有选中的项,则选择框的value保存空字符。如果有选中项或多个选中项,取第一个选中项作为参考。如果第一个选中项的value有值,则select的value值将设置与其相同;如果无值,则设置为option的文本值。针对上面的特点,下面是两个例子: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <form action="javascript:alert(1)"> <select> <option>1</option> <option>2</option> <option>3</option> <option>4</option> <option>5</option> <option>6</option> <option>7</option> <option>8</option> <option>9</option> <option>10</option> </select> </form> </input> <script> var select = document.forms[0].elements[0]; console.log(select.type);//select-one var options = select.options; console.log(options.length);//10 select.remove(0); select.remove({});//相当于remove(0) select.remove(9); select.remove( { valueOf:function(){ return 7; } } ); select.add(options[1], options[0]);//调换前两个选择的位置 </script> </body> </html> 在做select的value值实验前,我们来了解一下HTMLOptionElement类型。每个option都是该类型,该类型有下列额外的属性: index:当前选项在options集合中的索引。label:等价于label特性。selected:布尔值,表示当前选项是否被选中。将这个属性设置为true 可以选中当前选项。text:选项的文本。value:选项的值(等价于HTML 中的value 特性)。在未指定value 特性的情况下,IE8 会返回空字符串,而IE9+、Safari、Firefox、Chrome 和Opera 则会返回与text 特性相同的值。 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <form action="javascript:alert(1)"> <select name="location" id="selLocation"> <option value="Sunnyvale, CA">Sunnyvale</option> <option value="Los Angeles, CA">Los Angeles</option> <option value="Mountain View, CA">Mountain View</option> <option value="">China</option> <option>Australia</option> </select> </form> </input> <script> var select = document.forms[0].elements[0]; select.addEventListener("change", function (e) { var select = e.target; console.log(select.value); console.log(select.options[select.selectedIndex].value + "-----" + select.options[select.selectedIndex].text); }); /*select.attachEvent("onchange", function (e) { var select = e.srcElement; console.log(select.value == ""); console.log(select.options[select.selectedIndex].value + "-----" + select.options[select.selectedIndex].text); });*/ //IE代码 </script> </body> </html> ------------------------------ Los Angeles, CA Los Angeles, CA-----Los Angeles Sunnyvale, CA Sunnyvale, CA-----Sunnyvale Mountain View, CA Mountain View, CA-----Mountain View -----China //主动设置为"",将返回"" Australia Australia-----Australia //不设置value特性,可以理解成设置value=text(但是没有改变HTML) 针对上面最后一个特性,我想知道,这个是不是自动设置了value特性所造成的。于是我用getAttribute去获取option的value特性,结果发现是null。这说明了value属性与text相同,并不是自动设置了value特性。而应该是一种类似呼叫转移(这个词纯属胡诌)的行为。这个结果也给了我们一个启示:也就是前一篇文章开头提到的:对value 属性所做的修改,不一定会反映在DOM中。虽然value值与value特性息息相关,但是value值的变化并不都是反映了DOM中的value特性的变化,也可能是text的变化。所以要获取value值,千万不要通过getAttribute这种方式。通过常规DOM的方式去获取option元素的value与text的效率也会更低。所以我们在得到HTMLOptionElement对象后,要多去使用value和text属性而避免再通过getAttribute和innerHTML去获取value和text特性。

选择选项

选中选项有两种方式,一个是设置select元素的selectedIndex,另外一种则是设置option元素的selected。接下来分单选和多选框进行讨论。如果是单选框,那么selectedIndex的用法是没有疑问的,而selected就有一个问题:如果我设置了多个option的selected都为true,那会如何: <select name="location" id="selLocation"> <option value="Sunnyvale, CA" selected="true">Sunnyvale</option> <option value="Los Angeles, CA"selected="true">Los Angeles</option> <option value="Mountain View, CA"selected="true">Mountain View</option> <option value="">China</option> <option>Australia</option> </select> <script> var select = document.forms[0].elements[0]; console.log(select.options[0].selected);//fasle console.log(select.options[1].selected);//false console.log(select.options[2].selected);//true </script> ---------------------- 无论在何种浏览器中都是选中了第三个,可见这种行为只认最后一个的设置。 如果我单纯通过脚本去设置:结果一模一样 <script> var select = document.forms[0].elements[0]; select.options[0].selected = true; select.options[1].selected = true; select.options[2].selected = true; console.log(select.options[0].selected);//fasle console.log(select.options[1].selected);//false console.log(select.options[2].selected);//true </script> 如果是多选框,那selected可以不用讨论了,可以允许多个被选中,也就可以允许多个为true。但是selectedIndex的行为就很诡异。选中了多个选项,selectedIndex只会返回第一个被选中的选项的索引。如果通过脚本改变selectedIndex,则会只选中那一项,即使之前已经选中了很多项。例子就不举了。

添加选项

可以使用JavaScript 动态创建选项,并将它们添加到选择框中。添加选项的方式有很多,第一种方式就是使用如下所示的DOM 方法。 var newOption = document.createElement("option"); newOption.appendChild(document.createTextNode("Option text")); newOption.setAttribute("value", "Option value"); selectbox.appendChild(newOption); 第二种就是之前提到过的使用new Option(“Option text”, “Option value”);创建一个HTMLOptionElement对象,然后通过appendChild或者select元素独有的add方法去添加到DOM中。 var newOption = new Option("Option text", "Option value"); selectbox.appendChild(newOption); //在IE8 及之前版本中有问题 //下面是使用add方法,兼容DOM的浏览器要求必须有第二个参数。 selectbox.add(newOption, undefined); //添加到末尾的最佳方案

移除选项

除了最常规的DOM的removeChild()方法外,还可以使用select元素特有的remove()方法。这个方法传入一个索引即可使用,前面已经试验过了。还有一种遗留机制: selectbox.options[0] = null; //移除第一个选项 如果想要移除所有选项,可以遍历获取options的长度,然后执行长度次数的remove(0)即可(DOM都是动态的)。 for(var i=0, len=selectbox.options.length; i < len; i++){ selectbox.remove(0);//千万不要以为是remove(i),否则你会发现只能移除索引为偶数的option }

移动和重排选项

在DOM 标准出现之前,将一个选择框中的选项移动到另一个选择框中是非常麻烦的。整个过程要涉及从第一个选择框中移除选项,然后以相同的文本和值创建新选项,最后再将新选项添加到第二个选择框中。而使用DOM 的appendChild()方法,就可以将第一个选择框中的选项直接移动到第二个选择框中。我们知道,如果为appendChild()方法(insertBefore也可以)传入一个文档中已有的元素,那么就会先从该元素的父节点中移除它,再把它添加到指定的位置。 var selectbox1 = document.getElementById("selLocations1"); var selectbox2 = document.getElementById("selLocations2"); selectbox2.appendChild(selectbox1.options[0]); 而通过之前的add方法我们也可以移动位置 var selectbox1 = document.getElementById("selLocation1"); var selectbox2 = document.getElementById("selLocation2"); selectbox2.add(selectbox1.options[0], undefined);

表单序列化

随着Ajax 的出现,表单序列化已经成为一种常见需求(第21 章将讨论Ajax)。在JavaScript 中,可以利用表单字段的type 属性,连同name 和value 属性一起实现对表单的序列化。 对表单字段的名称和值进行URL 编码,使用和号(&)分隔。不发送禁用的表单字段。只发送勾选的复选框和单选按钮。不发送type 为”reset”和”button”的按钮。多选选择框中的每个选中的值单独一个条目。在单击提交按钮提交表单的情况下,也会发送提交按钮;否则,不发送提交按钮。也包括type为”image”的<input>元素。<select>元素的值,就是选中的<option>元素的value 特性的值。如果<option>元素没有value 特性,则是<option>元素的文本值。下面是书中给的序列化的代码: function serialize(form){ var parts = [], field = null, i, len, j, optLen, option, optValue; for (i=0, len=form.elements.length; i < len; i++){ field = form.elements[i]; switch(field.type){ case "select-one": case "select-multiple": if (field.name.length){ for (j=0, optLen = field.options.length; j < optLen; j++){ option = field.options[j]; if (option.selected){ optValue = ""; //在DOM 兼容的浏览器中需要使用hasAttribute()方法,而在IE 中需要使用特性的specified 属性。 if (option.hasAttribute){ optValue = (option.hasAttribute("value") ? option.value : option.text); } else { optValue = (option.attributes["value"].specified ? option.value : option.text); } parts.push(encodeURIComponent(field.name) + "=" + encodeURIComponent(optValue)); } } } break; case undefined: //fieldset case "file": //file input case "submit": //submit button case "reset": //reset button case "button": //custom button break; case "radio": //radio button case "checkbox": //checkbox if (!field.checked){ break; } /* falls through */ default: //don't include form fields without names if (field.name.length){ parts.push(encodeURIComponent(field.name) + "=" + encodeURIComponent(field.value)); } } } return parts.join("&"); }

富文本编辑

所谓富文本编辑就是我们可以在页面中建立一个文本编辑区,我们可以对其中的文本进行样式的设置,然后可以保持原样的将这段文本放置入页面的其他位置。故富文本编辑,又称为WYSIWYG(What You See Is What You Get,所见即所得)。就像博客下面的回复编辑区一样,我们可以改变字体大小或者颜色,提交后就可以保持原样地显示在回复区。这个功能可以说非常有用,那么该如何实现呢?这一技术的本质,就是在页面中嵌入一个包含空HTML 页面的iframe。通过设置designMode 属性,这个空白的HTML 页面可以被编辑,而编辑对象则是该页面<body>元素的HTML 代码。designMode 属性有两个可能的值:”off”(默认值)和”on”。在设置为”on”时(需在页面加载完成后设置,所以一般写在load事件处理程序内部),整个文档都会变得可以编辑(显示插入符号),然后就可以像使用字处理软件一样,通过键盘将文本内容加粗、变成斜体,等等。此外还可以使用contenteditable属性,可以把contenteditable 属性应用给页面中的任何元素,然后用户立即就可以编辑该元素。还可以在JS脚本中设置contenteditable属性,contenteditable属性有三个可能的值:true”表示打开、“false”表示关闭,“inherit”表示从父元素那里继承(因为可以在contenteditable 元素中创建或删除元素)。但是我实验下来发现这个contenteditable属性好像不能用,所以这里也不再放例子了。 <div class="editable" id="richedit" contenteditable></div>

操作富文本

与富文本编辑器交互的主要方式,就是使用document.execCommand()。这个方法可以对文档执行预定义的命令,而且可以应用大多数格式。可以为document.execCommand()方法传递3 个参数:要执行的命令名称、表示浏览器是否应该为当前命令提供用户界面的一个布尔值(为了兼容,这个参数应该始终为false)和执行命令必须的一个值(如果不需要值,则传递null)。以下是命令表: 下面是书中给的一个简单的富文本编辑例子: <!DOCTYPE html> <html> <head> <title>Rich Text Editing Example</title> </head> <body> <form method="post" action="javascript:alert('Form submitted!')"> <div id="divSimple"> <input type="button" value="Bold"> <input type="button" value="Italic"> <input type="button" value="Underline"> <input type="button" value="Indent"> <input type="button" value="Outdent"> <input type="button" value="Copy"> <input type="button" value="Cut"> <!--复制在IE中好用,在其他浏览器中可能被禁用了--> <input type="button" value="Paste"> </div> <div id="divComplex"> <input type="button" value="Create Link" id="btnCreateLink"> <input type="button" value="Change Font Size" id="btnChangeFontSize"> <input type="button" value="Highlight Text" id="btnHighlight"> <input type="button" value="Get HTML" id="btnGetHtml"> <input type="button" value="Get Selected Text" id="btnGetSelected"> </div> <div id="divQuery">Is the current selection: <input type="button" value="Bold"> <input type="button" value="Italic"> <input type="button" value="Underline"> </div> <iframe name="richedit" style="height: 500px; width: 1000px" src="blank.htm"></iframe> <input type="hidden" name="comments" value=""> <input type="submit" value="Submit Form"> </form> <script type="text/javascript"> (function(){ window.addEventListener("load", function(){ frames["richedit"].document.designMode = "on"; }); var simple = document.getElementById("divSimple"); var complex = document.getElementById("divComplex"); var queryDiv = document.getElementById("divQuery"); document.forms[0].addEventListener("submit", function(event){ event.target.elements["comments"].value = frames["richedit"].document.body.innerHTML; }); simple.addEventListener("click", function(event){ var target = event.target; if (target.type == "button"){ frames["richedit"].document.execCommand(target.value.toLowerCase(), false, null); } }); complex.addEventListener("click", function(event){ var target = event.target; switch(target.id){ case "btnGetHtml": alert(frames["richedit"].document.body.innerHTML); break; case "btnCreateLink": var link = prompt("What link?", "http://www.wrox.com"); if (link){ frames["richedit"].document.execCommand("createlink", false, link); } break; case "btnChangeFontSize": var size = prompt("What size? (1-7)", "7"); if (size){ frames["richedit"].document.execCommand("fontsize", false, parseInt(size,10)); } break; case "btnGetSelected": if (frames["richedit"].getSelection){ alert(frames["richedit"].getSelection().toString()); } else if (frames["richedit"].document.selection){ alert(frames["richedit"].document.selection.createRange().text); } break; case "btnHighlight": if (frames["richedit"].getSelection){ var selection = frames["richedit"].getSelection(); //get the range representing the selection var range = selection.getRangeAt(0); //highlight the selected text var span = frames["richedit"].document.createElement("span"); span.style.backgroundColor = "yellow"; range.surroundContents(span); } else if (frames["richedit"].document.selection){ var range = frames["richedit"].document.selection.createRange(); range.pasteHTML("<span style=\"background-color:yellow\">" + range.htmlText + "</span>"); } break; } }); queryDiv.addEventListener("click", function(event){ var target = event.target; if (target.type == "button"){ alert(frames["richedit"].document.queryCommandState(target.value.toLowerCase(), false, null)); } }); })(); </script> </body> </html>
转载请注明原文地址: https://www.6miu.com/read-37276.html

最新回复(0)