一,表单的基础知识
表单在HTML中表现为form标签,在javascript中是HTMLFormElement类型,拥有自己的和属性和方法
acceptCharset:服务器能够处理的字符集,等于HTML中accept-charset特性
action:接受请求的URL,等价于HTML的action
elements:表单所有控件集合
enctype:请求的编码类型,等于HTML的enctype
length:表单中的控件数量
method:要发送的HTTP请求类型,通常是get和post
name:表单的名称
reset():将表单域重置为默认值
submit():提交表单
target:用于发送请求和接受相应的窗口名称,等于HTML的target属性
获取form元素的方法,通过getElementById("ID"),document.forms[i],document.forms["name"],document.formname(不支持)
1,提交表单
<input type="submit" value="Submit">
<button type="submit">Submit</button>
<input type="image" src=".jpg">
以这种方法提交的表单,浏览器会将请求发送给服务器之前触发submit事件,这样就可以在提交到服务器前验证表单
调用EventUtil.preventDefault(event)取消提交表单
javascript代码中form.submit() 用以提交表单,不会触发submit事件,故提交前需要验证
避免重复提交表单,在第一次提交之后禁用提交按钮,或者利用onsubmit事件处理程序取消后续的表单提交
2,重置表单
<input type="reset" value="Reset">
<button type="reset">Reset</button>
点击重置按钮时会触发reset事件,可以在触发重置事件时,EventUtil.preventDefault(event)取消
javascript中,form.reset()事件可以触发重置事件
3,表单字段
每个表单有elements属性,是表单中所有表单元素的集合,是个有序列表,包含表单中所有字段
var form = document.getElementById("");
var field = form.elements[0];
var field2 = form.elements['name']; 如果有多个name值相同的表单元素,返回一个NodeList列表
var fieldcount = form.elements.length;
1)共有的表单字段属性
disabled:布尔值,表示当前字段是否被禁用
form:指向当前字段所属表单的指针
name:当前字段的名称
readOnly:布尔值,表示当前字段是否只读
tabIndex:表示当前字段的切换序号
type:当前字段的类型
value:字段被提交给服务器的值
只有form属性不能修改,其属性都可以通过js修改,
EventUtil.addHandler(form,"submit",function(event){ event = EventUtil.getEvent(event); var target = EventUtil.getTarget(event); var btn = target.elements[0]; btn.diaabled = true; 第一个提交之后,禁用提交事件 });
type 属性
单选select-one,多选select-multiple,自定义非提交按钮button,自定义提交按钮submit,重置reset,
2)共有的表单字段方法
focus() 获取焦点,一般在load事件触发时执行ducument.forms[0].focus()
HTML5为表单新增了一个autofocus属性,<input type="text" autofocus>
为实现兼容
EventUtil.addHandler(window,"load",function(event){ var element = document.forms[0] if(element.autofocus != true){ element.focus; console.log("JS,focus"); } });
blur(),取消焦点事件,document.forms[0].elements[0].blur();
3)共有的表单字段事件
blur事件:当前字段失去焦点时触发
change事件:对与input和textarea元素,当他们失去焦点且value值发生改变时触发,对于select元素当其选项改变时触发
focus事件,当前字段获得焦点时触发
var textbox = document.forms[0].elements[0]; EventUtil.addHandler(textbox,"focus",function(event){ event = EventUtil.getEvent(event); var target = EventUtil.getTarget(event); if(target.style.backgroundColor != "red"){ target.style.backgroundColor = "yellow"; } }); EventUtil.addHandler(textbox,"blur",function(event){ event = EventUtil.getEvent(event); var target = EventUtil.getTarget("event"); if(/[^d]/.test(target.value)){ target.style.backgroundColor = "red"; }else{ target.style.backgroundColor = ""; } }); EventUtil.addHandler(textbox,"change",function(event){ event = EventUtil.getEvent(event); var target = EventUtil.getTarget(event); if(/[^d]/.text(target.value)){ target.style.backgroundColor = "red"; }else{ target.style.backgroundColor = ""; } });
change 和 blur事件的先后顺便因浏览器而定
二,文本框脚本
<input type="text">
size属性:指定文本框中显示的字符数
vale属性:设置文本框的初始值
maxlength:指定文本框可以接受的最大字符数
<textarea></textarea>
rows指定文本框的行数,cols指定文本框的列数
初始值放在标签中间,不能设置textarea最大字符数
相同点,用户输入的内容都保存在value中,可以通过value读取用户输入的值
1,选择文本
文本框都支持select()方法,用于选择文本框中的所有文本,不接受参数,可以在任何时候被调用,一般设置在获取焦点的时候选择文本
1)select事件
在选择了文本框中的文本时,就会触发select事件,触发的时间因浏览器而异
2)取得选择的文本、
HTML5通过selectionStart和selectionEnd属性,保存基于0的数值,
function getSelectedText(textbox){
return textbox.value.subString(textbox.selectionStart,textbox.selectionEnd);
}
IE8以前不支持这两个属性,提供document.selection对象,保存着用户在整个文档范围内选择的文本信息
无法确定用户选择的是页面中哪个部位的文本,要获取选择的文本,首先创建一个范围
function getSelectedText(textbox){ if(typeof textbox.selectionStart == 'number'){ return textbox.value.substring(textbox.selectionStart,textbox.selectionEnd); }else if(document.selection){ return document.selection.createRange().text; } }
3)选择部分文本
文本框除拥有select()方法外,还有一个setSelectionRange()方法,接收两个参数,要选择的第一个字符的索引和要选择的最后一个字符之后的字符索引
text.value = "hello world";
textbox.setSelectionRange(0,textbox.value.length);
textbox.setSelectionRange(0,3);
textbox.setSelectionRange(4,7);
想要看到文本,必须在调用setSelectionRange()之前或之后立即将焦点设置到文本框
IE8及更早版本,要选择文本框中的部分文本,必须首先使用IE在所有文本框上提供的createTextRange()方法创建一个范围
在使用moveStart()和moveEnd()两个方法将范围移动到位,调用者两个方法前还要使用collapse()将范围折叠刀文本框的开始位置
此时moveStart()将范围的起点和终点移动到了相同的位置,只要给moveEnd()传人要选择的字符总数即可
最后一步就是使用范围的select()方法选择文本
textbox.value = "hello world";
var range = textbox.createtextRange();
range.collapse(true);
range.moveStart("charset",0);
range.moveEnd("charset",textbox.value.length);
ragne.select();
为了实践兼容
function selectText(textbox,startIndex,stopIndex){ if(textbox.setSelectionRange){ textbox.setSelectionRange(startIndex,stopIndex); }else if(textbox.createTextRange){ var range = textbox.createTextRange(); range.collapse(true); range.moveStar("charset",startIndex); range.moveEnd("charset",stopIndex-startIndex); range.select(); } textbox.focus(); }
2,过滤输入
1)屏蔽字符
EventUtil.addHandler(textbox,"keypress",function(event){ event = EventUtil.getEvent(event); var target = EventUtil.getTarget(event); var charCode = EventUtil.getCharCode(event); if(!/d/.test(String.fromCharCode(charCode)) && charCode > 9 && !event.ctrlKey){ EventUtil.preventDefault(event); } });
响应文本框输入字符的操作是keypress事件,屏蔽字符通过输入字符匹配正则表达式实现
charCode>9 保证上下键,退格,删除等键也会触发keypress事件,也要屏蔽
同时要保证复制粘贴的ctrl键可用
2)操作剪贴板
IE是第一个支持剪贴板的相关事件
beforecopy:在发生复制操作前触发
copy:在发生复制操作时触发
beforecut:在发生剪切操作前触发
cut:发生剪切操作时触发
beforepaste:在发生粘贴操作前触发
paste:在发生粘贴操作时触发
在实际的事件发生之前,可以通过beforecopy,beforecut,beforepaste事件向剪贴板发送数据,或从剪贴板取得数据之前修改数据
访问剪贴板的数据通过clipboardData对象,IE中是window对象的属性,其他DOM浏览器中是event对象的属性
在IE中随时可以访问clipboardData对象,其他DOM浏览器中只有在处理剪贴板事件期间对象才有效
clipboardData对象有三个方法,getData(),setData(),clearData()
getData(),用于从剪贴板中获取数据,接收一个参数为数据的格式,在IE中有text和URL两种值,其他DOM浏览器,参数是MIME类型,可以用text 代表text/plain
setData(),第一个参数也是数据类型,IE照常支付text和URL两种值,Safari和chrome不能识别text类型,第二个参数是要放在剪贴板中的文本,
为实现兼容
var EventUtil = { getClipboardData:function(event){ var clipboardData = (event.clipboardData || window.clipboardData); return clipboardData.getData("text"); }, setClipboardText:function(event){ if(event.clipboardData){ return event.clipboardData.setData("text/plain",value); }else if(window.clipboardData){ return window.clipboardData.setData('text',value); } }, };
3,自动切换焦点
在前一个文本框中的字符达到最大数后,自动将焦点切换到下一个文本框
<input type="text" name="tel1" id="text1" maxlength="3"> <input type="text" name="tel2" id="text2" maxlength="3"> <input type="text" name="tel3" id="text3" maxlength="4"> (function(){ function tabForward(event){ event = EventUtil.getEvent(event); var target = EventUtil.getTarget(event); if(target.value.length == target.maxLength){ var form = target.form; for(var i=0,len=form.elements.length;i<len;i++){ if(form.elements[i] == target){ form.elements[i+1].focus(); } return; } } } var textbox1 = document.getElementById("text1"); var textbox2 = document.getElementById("text2"); var textbox3 = document.getElementById("text3"); EventUtil.addHandler(text1,"keyup",tabForward); EventUtil.addHandler(text2,"keyup",tabForward); EventUtil.addHandler(text3,"keyup",tabForward); })();
4,HTML5约束验证API
1)必填字段
required属性,适用于input,textarea,select(Opera11之前还不支持select)
检验某个表单字段是否为必填字段
var isUsernameRequired = document.forms[0].elements["username"].required;
检验浏览器是否支持required属性
var isRequiredSupported = "required" in document.createElement("input");
2)其他输入类型
email,url,
3)数值范围
number,range,datetime,datetime-local,date,mouth,week,time
对所有数值类型的输入元素,可以指定min,max,step属性,
stepUp(),stepDown(),接受一个参数,在当前数值上加上或减去的数值,默认为1,目前尚没有浏览器支持
4)输入模式
pattern属性,正则表达式,用于匹配文本框中的值
<input type="text" pattern="d+" name="count">
通过pattern属性访问模式
var pattern = document.forms[0].elements["count"].pattern;
检测浏览器是否支持pattern属性
var isPatternsupport = "pattern" in document.createElement("input");
5)检测有效性
checkValidity()方法用于检测表单中某个字段是否有效,有效返回true,无效返回false
if(document.forms[0],elements[0].checkValidity()){}
if(document.forms[0].checkValidity()){}
Validity属性会告诉你为什么字段有效和无效,包含一系列属性
customError:如果设置了setCustomValue() 返回true,否则返回false
patternMismatch:如果值与指定的pattern属性不匹配,返回true
rangeOverflow:如果值比max大,返回true
rangeUnderflow:如果值比min小,返回true
stepMisMatch:如果在min和max之间的步长不合理,返回true
tooLong:如果超过了MaxLength,返回true
typeMismatch:如果值不是mail或url要求的格式 返回true
valid:如果这里的其他属性都是false,返回true
valueMissing:如果标注了required属性的元素没有值,返回true
6)禁用验证
设置novalidate属性,告诉表单不进行验证
<form method="post" action="sing.php" noValidate></form>
document.forms[0].noValidate = true 禁用验证
<input type="submit" formnovalidate>
document.forms[0].elements[0].formnovalidate = true 禁用验证
三,选择框脚本
选择框通过select和option元素创建,处理表单字段共享的属性外,还有下列的属性和方法
add(newOption,relOptin),在relOption之前添加新的option选项newOption,
multiple:布尔值,表示是否允许多选
options:控件中所有option元素的HTMLCollection
remove(index):移除给定位置的选项
selectedIndex:基于0的选中项的索引,没有项返回-1,对于多选项只保存第一项
size:选择框中可见的行数
选择框的value属性有当前选中项决定
没有选中的项,value属性保存空字符串
有一项选中,value已经在HTML中指定,则value属性等于选中项的value值
有一项选中,value值没有在HTML中给定,则value属性等于该项的文本
如果有多个项选中,value属性保存第一个选中项的值
DOM中每个option元素都是一个HTMLOptionElement对象表示,包含属性如下
index:当前选项在option集合中的索引
label:当前选项的标签
selected:布尔值,表示当前项是否被选中,设置为true可以选定当前的选项
text:选项的文本
value:选项的值
用于获取选项数据,var value = document.forms[0].elements["location"].options[0].value;
选择框的change事件只要选中了就会触发
1,选择选项
对于只允许选择一项的选择项
var selectedIndex = selectbox.selectedIndex;
var selectedOption = selectbox.options[selectedIndex]
var selectedOption = selectbox.options[selectbox.selectedIndex];
对于可以选择多项的选择框
selectedIndex只会返回选中项中第一项的索引值
selectbox.options[0].selected = true;
在允许多选的选择框中设置选项的selected属性,不会取消对其他选中项的选择,单选选择框中则会取消其他项的选择
function getSelectedOptions(selectbox){ var result = new Array(); var option = null; for(var i=0,len=selectbox.options.length;i<len;i++){ option = selectbox.options[i]; if(option.selected){ result.push(option); } } return result; }
2,添加选项
DOM方法
var newOption = document.createElement("option");
newOption.appendChild(document.createTextNode("Option text"));
newOption.setAttribute("value","Option value");
selectbox.appendChild(newOption);
Option构造函数来创建新选项,接收两个参数,text 和value
var newOption = new Option("Option text","Option value");
selectbox.appendChild(newOption);
使用add(newOption,relOption)添加
最后一个参数设置为undefined,则添加到列表最后一个选项
var newOption = new Option("option text","option value")
selectbox.add(newOption,undefined);
3,移除选项
selectbox.removeChild(selectbox,options[0]);
selectbox.remove();
selectbox.options[0] = null;
4,移动和重排选项
将一个选择框的选项移动到另一个选择框中
var selectbox1 = document.getElementById("selLocations1");
var selectbox2 = document.getElementById("selLocations2");
selectbox2.appendChild(selectbox1.options[0]);
移动选项和移除选项会重置每一个选项的index属性
向前移动一个选项的位置
var optionToMove = selectbox.options[1];
selectbox.insertBefore(optionToMove,selectbox.options[optionToMove.index-1]);
向后移动一个选项的位置
var optionToMove = selectbox.options[1];
selectbox.insertBefore(optionToMove,selectbox.options[optionToMove.index+2]);
四,表单序列化
1,浏览器是怎么将数据发给服务器的
1)对表单字段的名称和值进行URL编码,使用&分隔
2)不发送禁用的表单字段
3)只发送勾选的复选框和单选按钮
4)不发生type为reset和button的按钮
5)多选框中每个选中的值单独一个条目
6)点击提交按钮提交表单时,也发送提交按钮
7)select元素的值,就是选中的option元素的value值,没有时是text值
2,代码如下
function serialize(form){ var parts = [], field = null,i,len,j,optLen,option,optValue; for(i=0,len=form.elements.length;i<len;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 = ""; 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: case "file": case "submit": case "reset": case "button": break; case "radio": case "checkbox": if(!field.checked){ break; } default: if(field.name.length){ parts.push(endcodeURIComponent(field.name) + "=" + encodeURIComponent(field.value)); } } } return parts.join("&"); }
五,富文本编辑
所见即所得,本质是在页面中嵌入一个包含HTML页面的iframe,通过设置designMode属性,值为on时,HTML便可以编辑,默认值为off不可编辑
<iframe></iframe>
<script>
EventUtil.addHandler(window,"load","function(){
frames[richedit].document.designMode = "on";
}");
</script>
1,使用contenteditable属性
由IE最先实现,标签中设置contentedtable属性,用户就可以立即编辑该元素
可用通过div.contenteditable = "true"实现
contenteditable属性有三种,true,false,inherit
2,操作富文本
使用document.execCommand()方法实现与副文本编辑器交互的主要方式
接收三个参数,要执行的命令名称,表示浏览器是否应该为当前命令提供用户界面的一个布尔值,取false为好,和执行命令的一个值(不需要时传入null)
frames["richedit"].document.execCommand("bold",false,null);转换成粗体
frames["richedit"].document.execCommand("italic",false,null);转换成斜体
页面中contenteditable为true的区块
document.execCommand("bold",false,null);
document.execCommand("createlink",false,"http://www.wrox.com");
document.execCommand("formatblock",false,"<h1>");
还有一个queryCommandEnabled(),用来检测是否可以针对当前选择的文本,或者当前插入字符所在的位置执行某个命令,
接收一个参数,要检测的命令,如果当前编辑区域允许执行传人命令,返回true
var result = frames["richedit"].document.queryCommandEnabled("bold");
queryCommandState()方法用于确定是否已经将指定命令应用到了选择的文本
var isBold = frames["richedit"].document.queryCommandState("bold");
queryCommandValue(),用于取得执行命令时传人的值,即document.execCommand的第三个参数,
var fontSize = frames["richedit"].document.queryCommandValue("fontsize");
3,富文本选区
使用getSelection()方法,可以确定实际选择的文本,这个方法时window对象和document对象的属性
调用会返回Selection对象,其属性如下
anchorNode:选区起点所在的节点
anchorOffset:到达选区起点位置之前跳过的anchorNode中的字符数量
focusNode:选区终点所在的节点
focusoffset:focusNode中包含在选区之内的字符数量
isCollapsed:布尔值,表示选区的起点和终点是否重合
rangeCount:选区中包含的DOM范围的数量
addRange():将指定的DOM范围添加到选区中
collapse(node,offset),将选区折叠刀指定节点中的相应的文本偏移位置
collapseToEnd():将选区折叠刀终点位置
collapseToStart():将选区折叠刀起点位置
containsNode(node):确定指定的节点是否包含在选区中
deleteFromDocument():从文档中删除选区中的文本,document.execCommand("delete",false,null);
extend(Node,offset):将focusNode和focusOffset移动到指定的值来扩展选区
getRangeAt(index):返回索引对应的选区中的DOM范围
removeRange(range):返回索引对应的选区中的DOM范围
removeAllRanges():从选区中移除所有DOM范围
removeRange(range):从选区中移除指定的DOM范围
selectAllChildren(node):移除选区并选择指定节点的所有子节点
toString(),返回选区包含的文本内容
var selection = frames["richedit"].getSelection(); var selectedText = selection.toString(); var range = selection.getRangeAt(0); var span = frames["richedit"].document.createElement("span"); span.style.backgroundColor = "yellow"; range.surroundContents(span);
var range = frames["richedit"].document.selection.createRange(); var selectedText = ragne.text;
var range = frames["richedit"].document.selection.createRange(); range.pasteHTML("<span style="background-color:yellow">" + "</span>");
4,表单与富文本
富文本编辑器中的HTML不会自动提交给服务器,
为此可以添加一个隐藏的表单字段,让它的值等于iframe中提取的HTML,在提交表单之前从iframe中提取HTML,
将其隐藏在字段中,
EventUtil.addHandler(form,"submit",function(event){ event = EventUtil.getEvent(event); var target = EventUtil.getTarget(event); target.elements["comments"].value = frames["richedit"].document.body.innerHTML; });