本章主要介紹:表單潮罪、文本框驗(yàn)證與交互沃暗、使用其他表單控制嚼黔。這一章會(huì)繼續(xù)沿用上一章 封裝的 EventUtil 對(duì)象(具體參考前面的
事件)
JavaScript最初的一個(gè)應(yīng)用,就是分擔(dān)服務(wù)器處理表單的責(zé)任碎节,打破處處依賴服務(wù)器的局面
一、表單的基礎(chǔ)知識(shí)
JavaScript中创坞,表單對(duì)應(yīng)的是 HTMLFormElement 類型偎谁。HTMLFormElement 繼承了 HTMLElement。HTMLFormElement 有自己下列獨(dú)有的屬性和方法
- acceptCharset:服務(wù)器能夠處理的字符集:等價(jià)于HTML中的 accpet-charset 特性
- action:接受請(qǐng)求的URL:等價(jià)于HTML中的 action 特性。
- elements:表單中所有控件的集合(HTMLCollection)
- enctype:請(qǐng)求的編碼類型正蛙;等價(jià)于HTML 中的 enctype 特性
- length:表單中控件的數(shù)量
- method:要發(fā)送的HTTP請(qǐng)求類型,通常是“get” 或 “post”狂塘;等價(jià)于 HTML 的method特性。
- name:表單的名稱;等價(jià)于HTML 的name 特性
- reset():將所有表單域重置為默認(rèn)值
- submit():提交表單
- target:用于發(fā)送請(qǐng)求和接受響應(yīng)的窗口名稱窖梁;等價(jià)于 HTML 的target 特性。
取得<form>元素 引用的方式有好幾種:最常見的方式是 使用 getElementById() 方法找到它
var form = document.getElementById('myForm')
其次,通過document.forms 獲取頁面中所有的表單,再通過 索引 或 name值 來訪問
var firstForm = document.forms[0] // 獲取頁面中的第一個(gè)表單
var myForm = document.forms['form2'] // 獲取頁面中 名稱為 “form2” 的表單
在較早的瀏覽器或者那些支持向后兼容的瀏覽器中惧蛹,也會(huì)把每個(gè)設(shè)置了 name 特性的 表單作為屬性保存在 document 對(duì)象中。通過document.form2 可以訪問到名為 "form2" 的表單。
1.1、提交表單
使用 <input> 或 <button> 都可以定義提交按鈕苫费,只要將其 type 特性的值設(shè)置為 "submit" 即可,而圖像按鈕則是通過將 <input> 的 type 特性值設(shè)置為 “image” 來定義
<!-- 通用提交按鈕 -->
<input type="submit" value="Submit Form" />
<!-- 自定義提交按鈕 -->
<button type="submit">Submit Form</button>
<!-- 圖像按鈕 -->
<input type="image" src="graphic.gif" />
以這種方式提交表單時(shí)柬泽,瀏覽器會(huì)在將請(qǐng)求發(fā)送給服務(wù)器之前觸發(fā) submit 事件。這樣,我們就有機(jī)會(huì)驗(yàn)證表單數(shù)據(jù),并決定是否允許提交表單害晦。
var form = document.getElementById('myForm')
EventUtil.addHandler(form, 'submit', function(event){
// 取得事件對(duì)象
event = EventUtil.getEvent(event)
// if () {
// 阻止默認(rèn)事件
EventUtil.preventDefault(event)
// }
})
在JavaScript中鳄逾,以編程方式調(diào)用 submit() 方法也可以提交表單澄者。這種方式無需表單包含提交按鈕赠幕。任何時(shí)候都可以正常提交表單竖慧。
var from = document.getElementById('myForm')
// 提交表單
form.submit()
調(diào)用 submit() 方法提交表單的形式魏蔗,不會(huì)觸發(fā) submit事件廓鞠,因此要記得在調(diào)用此方法之前先驗(yàn)證表單數(shù)據(jù)滋早。
提交表單時(shí)可能出現(xiàn)的最大問題,就是重復(fù)提交表單。為此,可以在在第一次提交表單后就禁用提交按鈕,或者利用 onsubmit 事件處理程序取消后續(xù)的表單提交操作萧吠。
1.2梅忌、重置表單
使用 type 特性值為 “reset”的 <input> 或 <button> 都可以創(chuàng)建重置按鈕琼腔,
<!-- 通用重置按鈕 -->
<input type="reset" value="Reset Form">
<!-- 自定義重置按鈕 -->
<button type="reset">Reset From</button>
也可以使用 JavaScript 的方式 來重置表單
var form = document.getElementById('myForm')
// 重置表單
from.reset()
用戶單擊重置按鈕重置表單時(shí),會(huì)觸發(fā) reset 事件。我們可以在必要時(shí)取消重置操作
/* 阻止重置表單操作 */
var form = document.getElementById('myForn')
form.onreset = function(event) {
event.preventDefault()
}
1.3、表單字段
每個(gè)表單都有一個(gè) elements 屬性悲敷,該屬性是表單中所有表單元素(字段)的集合。可以按照位置和 name 特性來訪問它們,
var form = document.getElementById('myForm')
// 取得表單中的第一個(gè)字段
var field1 = form.elements[0]
// 取得表單中name 為 textbox1的字段
var field2 = form.elements['textbox1']
// 取得表單中包含的字段的數(shù)量
var fieldCount = from.elements.length
如果使用 name 實(shí)現(xiàn)訪問元素時(shí),多個(gè)表單控件的 name 相同筏勒,就會(huì)返回一個(gè) 以改name 命名的 NodeList邪媳,然后可以通過 索引 訪問這個(gè)集合中的元素
如下
<input type="radio" name="color" value="red"> red
<input type="radio" name="color" value="cyan"> cyan
<input type="radio" name="color" value="violet"> violet
<script>
var colors = document.forms[0]['color']
console.log(Object.prototype.toString.call(colors))
console.log(colors[0]) // 第一個(gè) 單選框
</script>
1.3.1、共有的表單字段屬性
除了 <fieldset> 元素之外逗柴,所有的表單字段都擁有相同的一組屬性屠尊。
表單字段共有的屬性如下。
- disabled:布爾值闰围,表示當(dāng)前字段是否被禁用
- form:指向當(dāng)前字段所屬表單的指針运敢;只讀迄沫。
- name:當(dāng)前字段的名稱
- readOnly:布爾值盼砍,表示當(dāng)前字段是否只讀
- tabIndex:表示當(dāng)前字段的切換(tab)序號(hào)
- type:當(dāng)前字段的類型,入“checkbox“侧戴、”radio“,等等。
- value:當(dāng)前字段將被提交給服務(wù)器的值。對(duì)文件字段來說,這個(gè)屬性是只讀的,包含文件在計(jì)算機(jī)中的路徑
超級(jí) form屬性之外慨默,可以通過 JavaScript 動(dòng)態(tài)的修改其他屬性的值。
var form = document.getElementById('myForm')
var field = form.elements[0]
// 修改 value 屬性
field.value = "Another value"
// 檢查 form 屬性值
alert(field.form == form) // true
// 把焦點(diǎn)設(shè)置當(dāng)前字段
field.focus()
// 禁用當(dāng)前字段
field.disabled = true
// 修改 type 屬性(不推薦,但對(duì)于 <input> 元素來說是可行的)
field.type = "checkbox"
避免多次提交,最常見的解決方案,就是在第一次單機(jī)后就禁用提交按鈕。
// 避免多次提交表單
EventUtil.addHandler(form, 'submit', function(event) {
event = EventUtil.getEvent(event)
var target = EventUtil.getTarget(event)
// 取得提交按鈕
var btn = target.elements['submit-btn']
// 禁用它
btn.disabled = true
})
注意不能通過 onclick 事件處理程序來實(shí)現(xiàn)這個(gè)功能,原因是不同瀏覽器之間存在”時(shí)差“:有點(diǎn)瀏覽器會(huì)在觸發(fā)表單的 submit 事件之前觸發(fā) click 事件,意味著會(huì)在提交發(fā)生之間禁用按鈕,結(jié)果永遠(yuǎn)都不會(huì)提交表單
除了 <fieldset> 之外涨椒,所有表單字段都有 type 屬性。對(duì)于 <input> 元素绽媒,這個(gè)值等于 HTML 特性 type 的值蚕冬。對(duì)于其他元素,這個(gè) type 屬性的值如下表所列:
說明 | HTML示例 | type 屬性的值 |
---|---|---|
單選列表 | <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 屬性是可以動(dòng)態(tài)修改的播瞳,而 <select> 元素的 type 屬性則是只讀的。
1.3.2免糕、共有的表單字段方法
每個(gè)表單字段都有兩個(gè)方法:focus() 和 blur()。
focus() 方法用于將瀏覽器的焦點(diǎn)設(shè)置到表單字段,級(jí)激活表單字段石窑,使其可以響應(yīng)鍵盤事件牌芋。為此,可以偵聽頁面的 load 事件松逊,并在該事件發(fā)生時(shí)在表單的第一個(gè)字段上調(diào)用 focus() 方法躺屁,如下:
EventUtil.addHandler(window, 'load' , function(event) {
document.forms[0],elements[0].focus()
})
需要注意的是:如果 focus() 方法的對(duì)象是一個(gè) type="hidden" 的 <input> 元素的話,那么以上代碼會(huì)導(dǎo)致錯(cuò)誤经宏。另外犀暑,如果使用 CSS 的 display 和 visibility 屬性隱藏了該字段,同樣也會(huì)導(dǎo)致錯(cuò)誤
HTML5 為表單字段新增了一個(gè) autofocus 屬性烁兰。在支持這個(gè)屬性的瀏覽器中耐亏,只要設(shè)置這個(gè)屬性不用 JavaScript就能自動(dòng)把焦點(diǎn)移動(dòng)到相應(yīng)字段。例如:
<input type="text" autofocus />
可以通過 autofocus 屬性獲取 元素上面的 autofocus 的狀態(tài)沪斟,在支持的瀏覽器中如果設(shè)置了為true
blur() 作用是從元素上移走焦點(diǎn)
document.forms[0].elements[0].blur()
1.3.3广辰、共有的表單字段事件
所有的表單字段都支持下列三個(gè)事件
- blur:當(dāng)前字段市區(qū)焦點(diǎn)時(shí)觸發(fā)
- change:對(duì)于<input> 和 <textarea> 元素,它們失去焦點(diǎn)且 value 值改變時(shí)觸發(fā)主之;對(duì)于 <select> 元素择吊,在其選項(xiàng)改變時(shí)觸發(fā)
- focus:當(dāng)前字段獲得焦點(diǎn)時(shí)觸發(fā)
change 事件經(jīng)曾用于驗(yàn)證用戶在字段中輸入的數(shù)據(jù)。
下面例子中槽奕,對(duì)上訴三個(gè)事件簡單使用
var textbox = document.forms[0].elements[0]
EventUtil.addHandler(textbox, "focus", function(event) { // 獲得焦點(diǎn)時(shí) 編程黃色
event = EventUtil.getEvent(event)
var target = EventUtil.getTarget(event)
if (target.style.backgroundColor != 'red') {
target.style.backgroundColor = 'yellow'
}
})
EventUtil.addHandler(textbox, "blur", function(event) { // 失去焦點(diǎn)
event = EventUtil.getEvent(event)
var target = EventUtil.getTarget(event)
// 驗(yàn)證用戶是否輸入的是數(shù)字
if (/[^\d]/.test(target.value)) {
target.style.backgroundColor = 'red'
} else {
target.style.backgroundColor = ''
}
})
EventUtil.addHandler(textbox, "input", function(event) { // value 值變化時(shí)
event = EventUtil.getEvent(event)
var target = EventUtil.getTarget(event)
console.log(target.value)
// 驗(yàn)證用戶是否輸入的是數(shù)字
if (/[^\d]/.test(target.value)) {
console.log(1)
target.style.backgroundColor = 'red'
} else {
target.style.backgroundColor = ''
}
})
因?yàn)?change 事件必須 在value值改變且失去焦點(diǎn)才會(huì)觸發(fā)几睛,所以這里用 input 事件來實(shí)時(shí)監(jiān)聽
二、文本框腳本
在 HTML 中粤攒,有兩種方式來表現(xiàn)文本框所森,<input> 、<textarea> 兩種元素
<input>
- 通過設(shè)置 size 特性琼讽,可以指定文本框中能夠顯示的字符數(shù)
- 通過value特性必峰,可以設(shè)置文本框的初始值
- 通過maxlength特性則用于指定文本框 可以接受的最大字符數(shù)
<textarea>
- rows特性指定文本框的字符行數(shù)
- cols 特性指定文本框的字符列數(shù)
與 <Input> 元素不同,<textarea>的初始值必須要放在 <textarea></textarea>之間
<textarea rows="25" cols="5"> initial value </textarea>
值得注意的時(shí):在操作 value 屬性時(shí)钻蹬,不建議使用 標(biāo)準(zhǔn)的 DOM 方法(setAttribute())吼蚁,這樣對(duì) value 屬性所作的修改,不一定會(huì)反映在 DOM 中
2.1问欠、選擇文本
上訴兩種文本框都支持 select() 方法肝匆,這個(gè)方法用于選擇文本框中的所有文本。在調(diào)用 select() 方法時(shí)顺献,大多數(shù)瀏覽器都會(huì)將焦點(diǎn)設(shè)置到 文本框中
var textbox = document.forms[0].elements["textarea"]
textbox.select()
在文本框獲得焦點(diǎn)時(shí)選擇其所有文本旗国,這是一種非常常見的做法,特別是在 文本框包含默認(rèn)值的時(shí)候注整。因?yàn)檫@樣做可以讓用戶不必一個(gè)一個(gè)地刪除文本能曾。
EventUtil.addHandler(textbox, "focus", function(event) {
event = EventUtil.getEvent(event)
var target = EventUtil.getTarget(event)
target.select()
})
2.1.1度硝、select 事件
與 select() 方法對(duì)應(yīng)的,有一個(gè) select 事件寿冕,在選擇了文本框的文本是蕊程,就會(huì)觸發(fā)select事件,而在IE8及更早版本中驼唱,只要用戶選擇了一個(gè)字母(不必釋放鼠標(biāo))藻茂,就會(huì)觸發(fā)select 事件。另外玫恳,在調(diào)用 select() 方法時(shí)也會(huì)觸發(fā) select 事件辨赐。
var textbox = document.forms[0].elements['textbox1']
EventUtil.addHandler(textbox, "select", function(event) {
console.log("select text")
})
當(dāng)用戶選擇 textbox 中的文本時(shí),就會(huì)觸發(fā)這個(gè)事件 京办,輸出 select text
2.1.2掀序、取得選擇的文本
通過 select 事件我們可以知道用戶什么時(shí)候選擇了文本,但任然不知道用戶選擇了什么文本臂港。 HTML5 通過了一些 擴(kuò)展方案解決了這個(gè)問題森枪。添加了兩個(gè)屬性:selectionStart 和 selectionEnd。 這兩個(gè)屬性中保存的是基于 0 的數(shù)值审孽,表示所選擇文本的范圍(即文本選區(qū)開頭和結(jié)尾的偏移量)县袱。
function getSelectedText(textbox) {
return textbox.value.substring(textbox.selectionStart, textbox.selectionEnd)
}
// 獲取選區(qū)的文本
var textbox = document.forms[0].elements["textarea"]
EventUtil.addHandler(textbox, "select", function(event) {
// 調(diào)用方法
console.log("select Text :" + getSelectedText(textbox))
})
IE8及之前不支持這兩個(gè)屬性而是提供了另一種方案
IE8及更早的版本中有一個(gè) document.selection 對(duì)象,其中保存著用戶在整個(gè)文檔范圍內(nèi)選擇的文本信息佑力,與 select 事件一起使用的時(shí)候式散,可以假定是用戶選擇了文本框中的文本。要取得選擇的文本打颤,首先必須創(chuàng)建一個(gè)范圍暴拄,然后再將文本從其中提取出來。
function getSelectedText(textbox) {
if (typeof textbox.selectionstart === 'number') {
return textbox.value.substring(textbox.selectionStart, textbox.selectionEnd)
} else if(document.selection) { // 針對(duì) IE
return document.selection.createRange().text
}
}
2.1.3编饺、選擇部分文本
HTML5 也為選擇文本框中的部分文本提供了解決方案乖篷,所有文本款都有一個(gè) setSelectionRange() 方法,這個(gè)方法接收兩個(gè)參數(shù):要選擇的第一個(gè)字符的索引透且、選擇的最后一個(gè)字符之后的字符的索引
var textbox = document.forms[0].elements["textarea"]
textbox.value = 'Hello World!'
textbox.select() // 使當(dāng)前 獲取焦點(diǎn)
// 選擇所有文本
textbox.setSelectionRange(0, textbox.value.length)
// 選擇前3個(gè)字符
textbox.setSelectionRange(0, 3)
// 選擇第 4-6 個(gè)字符
textbox.setSelectionRange(4, 7)
要看到選擇的文本撕蔼,必須在調(diào)用 setSelectionRange() 之前或之后立即將焦點(diǎn)設(shè)置到文本框
IE8及更早版本,要選擇文本框中的部分文本秽誊,
- 首先使用 IE 在所有文本框是 提供的 createTextRange() 方法創(chuàng)建一個(gè)范圍鲸沮,
- 然后 使用 moveStart() 和 moveEnd() 這兩個(gè)范圍方法將范圍移動(dòng)到位
- 在調(diào)用這兩個(gè)方法之前,還必須使用 collapse() 將范圍折疊到文本框的開始位置
- 使用 范圍的 select() 方法選擇文本
var textbox = document.forms[0].elements["textarea"]
textbox.value = 'Hello World!'
var range = textbox.createTextRange()
// 選擇所有文本
range.collapse(true)
range.moveStart('character', 0)
range.moveEnd('character', textbox.value.length)
range.select()
// 選擇前3個(gè)字符
range.collapse(true)
range.moveStart('character', 0)
range.moveEnd('character', 3)
range.select()
實(shí)現(xiàn)跨瀏覽器編程锅论,結(jié)合上訴兩種方案組合
function selectText(textbox, startIndex, endIndex) {
if (textbox.setSelectionRange) {
textbox.setSelectionRange(startIndex, endIndex)
} else if(textbox.createTextRange) { // IE
var range = textbox.createTextRange() // 創(chuàng)建范圍
range.collapse(true) // 折疊范圍
// 移動(dòng)范圍
range.moveStart('character', startIndex)
range.moveEnd('character', endIndex)
range.select() // 選擇文本
}
// 獲取焦點(diǎn)
textbox.focus()
}
可以像下面這樣使用這個(gè)方法
var textbox = document.forms[0].elements['textarea']
textbox.value = 'Hello World'
// 選擇所有文本
selectText(textbox, 0, textbox.value.length)
2.2讼溺、過濾輸入
我們經(jīng)常會(huì)要求用戶在文本框中輸入特定的數(shù)據(jù),或者輸入特定格式的數(shù)據(jù)最易。綜合運(yùn)用事件和DOM手段怒坯,可以將普通的文本框轉(zhuǎn)換成能夠理解用戶輸入數(shù)據(jù)的功能型控件炫狱。
2.2.1、屏蔽字段
響應(yīng)向文本框中插入字符操作的是 keypress 事件剔猿。因此毕荐,可以通過阻止這個(gè)事件的默認(rèn)行為來屏蔽此類字符。
EventUtil.addHandler(textbox, 'keypress', function(event) {
event = EventUtil.getEvent(event)
EventUtil.preventDefault(event)
})
如果只想屏蔽特定字符艳馒,則需要檢測(cè) keypress 事件對(duì)應(yīng)的字符編碼,然后再?zèng)Q定如何響應(yīng)员寇。
// 只允許輸入數(shù)值弄慰。
EventUtil.addHandler(textbox, 'keypress', function(event) {
event = EventUtil.getEvent(event)
var target = EventUtil.getTarget(event)
var charCode = EventUtil.getCharCode(event) // 獲取當(dāng)前的 鍵碼
if (! (/\d/.test(String.fromCharCode(charCode)))) { // 獲取鍵碼對(duì)應(yīng)字符在進(jìn)行正則檢測(cè) 取反
EventUtil.preventDefault(event)
}
})
僅考慮屏蔽不是數(shù)值的字符還不夠,還要避免屏蔽一些極為常用和必要的鍵蝶锋。所幸的是陆爽,要檢測(cè)這些鍵并不困難。
在Firefox中扳缕,所有由非字符鍵觸發(fā)的 keypress 事件對(duì)應(yīng)的字符編碼為0
在 Safari 以前的版本中慌闭,對(duì)應(yīng)的字符編碼全部為8
為了讓代碼更通用,只要不屏蔽那些字符編碼小于10的鍵即可
// ...
if (!(/\d/.test(String.fromCharCode(charCode))) && charCode > 9) {
EventUtil.preventDefault(event)
}
除此之外還有一個(gè)文本需要處理:復(fù)制躯舔、粘貼及其他操作還有用到 Ctrl 鍵驴剔。在除IE之外的所有瀏覽器中,前面的代碼也會(huì)屏蔽 Ctrl + C粥庄、Ctrl + V丧失,以及其他使用 Ctrl 的組合鍵。因此最后還要添加一個(gè)檢測(cè)條件惜互,以確保用戶沒有按下啊 Ctrl 鍵布讹。
if (! (/\d/.test(String.fromCharCode(charCode))) && charCode > 9 && !event.ctrlKey) {
EventUtil.preventDefault(event)
}
2.2.2、操作剪貼板
IE 是第一個(gè)支持與剪貼板有關(guān)事件训堆,以及通過 JavaScript 訪問剪貼板數(shù)據(jù)的瀏覽器, HTML5后來也把剪貼板事件納入了規(guī)范
- beforecopy:在發(fā)生復(fù)制操作當(dāng)前觸發(fā)描验。
- copy:在發(fā)生復(fù)制操作時(shí)觸發(fā)
- beforecut:在發(fā)生剪切操作前觸發(fā)
- cut:在發(fā)生剪切操作時(shí)觸發(fā)
- beforepaste:在發(fā)生粘貼操作前觸發(fā)
- paste:在發(fā)生粘貼操作時(shí)觸發(fā)
由于沒有針對(duì)剪貼板操作的標(biāo)準(zhǔn),這些事件及相關(guān)對(duì)象會(huì)因?yàn)g覽器而異坑鱼。在Safari膘流、Chrome 和 Firefox中,
beforecopy姑躲、beforecut睡扬、beforepaste 事件只會(huì)在顯示在針對(duì)文本框的上下文菜單(預(yù)期發(fā)生剪貼板事件)的情況下觸發(fā)。
但是黍析,IE則會(huì)在觸發(fā) copy卖怜、cut和paste事件之前先觸發(fā)這些事件
。至于 copy阐枣、cut和paste事件马靠,只要是在上下文菜單中選擇了相應(yīng)選項(xiàng)奄抽,或者使用了相應(yīng)的鍵盤組合鍵,所有瀏覽器都會(huì)觸發(fā)它們甩鳄。
在實(shí)際的事件發(fā)生之前
逞度,通過 beforecopy、beforecut妙啃、beforepaste事件可以在像剪貼板發(fā)送數(shù)據(jù)档泽,或者從剪貼板取得數(shù)據(jù)之前修改數(shù)據(jù)。不過揖赴,取消這些事件并不會(huì)取消對(duì)剪切板的操作——只有取消 copy馆匿、cut、paste 事件燥滑,才能阻止響應(yīng)操作發(fā)生渐北。
要訪問剪貼板中的數(shù)據(jù),可以使用 clipboardData 對(duì)象:在IE中铭拧,這個(gè)對(duì)象是 window 對(duì)象的 屬性
赃蛛;而在 Firefox 4+、Safari 和 Chrome 中搀菩,這個(gè)對(duì)象是相應(yīng) event 對(duì)象的屬性
呕臂。但是,在Firefox秕磷、Safari诵闭、Chrome 中,只有在處理剪貼板事件期間澎嚣,clipboardData對(duì)象才有效疏尿,這是為了防止對(duì)剪貼板的未授權(quán)訪問
;在IE中易桃,則可以隨時(shí)訪問 clipboardData 對(duì)象褥琐。為了確保跨瀏覽器兼容晤郑,最好只在發(fā)生剪貼板事件期間使用這個(gè)對(duì)象敌呈。
clipboardData 對(duì)象有三個(gè)方法
-
getDate() 用于從剪貼板中獲取數(shù)據(jù),
- 接受一個(gè)參數(shù)造寝,即要取得的數(shù)據(jù)格式磕洪,
在IE中,有兩種數(shù)據(jù)格式:“text”诫龙、“URL”
在Firefox析显、Safari、Chrome中签赃,這個(gè)參數(shù)是一種MIME類型谷异,可以使用“text”代表“text/plain”
- 接受一個(gè)參數(shù)造寝,即要取得的數(shù)據(jù)格式磕洪,
-
setData() 設(shè)置數(shù)據(jù)
- 數(shù)據(jù)類型
IE支持:text分尸、URL
而 Safaru 和 Chrome 只支持 MIME 類型,不能代替 - 放在剪貼板中的文本歹嘹。
- 數(shù)據(jù)類型
clearData():清除數(shù)據(jù)
在成功將文本放到剪貼板中后箩绍,都會(huì)返回true;否則返回false
為了彌補(bǔ)這些差異尺上,我們可以項(xiàng) EventUtil 中再添加下列方法:
var EventUtil = {
// 獲取剪貼板中的 文本
getClipboardText: function(event) {
var clipboardData = (event.clipboardData || window.clipboardData)
return clipboardData.getData('text')
},
// 設(shè)置 剪貼板中的文本
setClipboardText: function(event, value) {
if (event.clipboardData) return event.clipboardData.setData('text/plain', value)
else if(window.clipboardData) return window.clipboardData.setData('text', value)
}
}
在需要確保粘貼到文本框中的文本中包含某些字符材蛛,或者符合某種格式要求時(shí),能夠訪問剪貼板是非常有用的怎抛。在paste事件中仰税,可以確定剪貼板中的事件是否有效
EventUtil.addHandler(textbox, 'paste', function(event) {
event = EventUtil.getEvent(event)
var text = EventUtil.getClipboardText(event)
console.log(1)
if (!/^\d*$/.test(text)) {
EventUtil.preventDefault(event)
}
})
如上代碼只會(huì)在,粘貼板中文本內(nèi)容只包含數(shù)字的時(shí)候抽诉,才能粘貼
由于并非所有瀏覽器都支持訪問剪貼板,所以更簡單的做法是屏蔽一或多個(gè)剪貼板操作
2.3吐绵、自動(dòng)切換焦點(diǎn)
使用 JavaScript 可以從多個(gè)方面增強(qiáng)表單字段的易用性迹淌。其中,最常用的一種方式就是在用戶填寫完當(dāng)前字段時(shí)己单,自動(dòng)將焦點(diǎn)切換到下一個(gè)字段唉窃。
例如,美國的電話號(hào)碼通常分為三個(gè)部分:區(qū)號(hào)纹笼、局號(hào)纹份、另外4位數(shù)字。為取得完整的電話號(hào)碼廷痘,很多網(wǎng)頁中都會(huì)提供下列3個(gè)文本框蔓涧,如下DOM結(jié)構(gòu)
<input type="text" name="tel1" id="txtTel1" maxlength="3">
<input type="text" name="tel2" id="txtTel2" maxlength="3">
<input type="text" name="tel3" id="txtTel3" maxlength="4">
為了增強(qiáng)易用性,同時(shí)加快數(shù)據(jù)輸入笋额,可以在前一個(gè)文本框中的字符達(dá)到最大數(shù)量后元暴,自動(dòng)將焦點(diǎn)切換到下一個(gè)文本框
function tabForward(event) {
event = EventUtil.getEvent(event)
var target = EventUtil.getTarget(event) // 獲取當(dāng)前DOM元素
if (target.value.length == target.maxLength) { // 如果 輸入完畢(最大長度)
var form = target.form // 獲取 當(dāng)前字段的 form
for(var i = 0, len = form.elements.length; i < len; i++){ // 遍歷
if (form.elements[i] == target) { // 當(dāng)前元素
if (form.elements[i + 1]) { // 如果存在 下一個(gè)元素
form.elements[i + 1].focus() // 下一個(gè)元素獲得焦點(diǎn)
return
}
}
}
}
}
var textbox1 = document.getElementById('txtTel1')
var textbox2 = document.getElementById('txtTel2')
var textbox3 = document.getElementById('txtTel3')
EventUtil.addHandler(textbox1, 'keyup', tabForward)
EventUtil.addHandler(textbox2, 'keyup', tabForward)
EventUtil.addHandler(textbox3, 'keyup', tabForward)
不過請(qǐng)記住,這些代碼只適用于前面給出的標(biāo)記兄猩,沒有考慮隱藏字段
2.4茉盏、HTML5約束驗(yàn)證API
為了在將表單提交到服務(wù)器之前驗(yàn)證數(shù)據(jù),HTML5新增了一些功能枢冤。有了這些功能鸠姨,幾遍JavaScript被禁用或者由于種種原因未能加載,也可以確毖驼妫基本的驗(yàn)證
2.4.1讶迁、必填字段
required 屬性
<input type="text" name="username" required />
在JavaScript中,通過對(duì)應(yīng)的required 屬性趟咆,可以檢查某個(gè)表單字段是否為必填字段
var isUsernameRequired = document.forms[0].elements["username"].required
另外添瓷,使用下面這行代碼可以測(cè)試瀏覽器是否支持required屬性
var isRequiredSupported = "required" in document.createElement("input")
對(duì)于空著的必填字段梅屉,不同瀏覽器有不同的處理方式。Firefox4和Opera11會(huì)阻止表單提交并在相應(yīng)字段下發(fā)彈出幫助框鳞贷,而Safari5-坯汤、Chrome9-則什么也不做,而且也不會(huì)阻止表單提交搀愧。現(xiàn)在的瀏覽器以便都會(huì)阻止提交
2.4.2惰聂、其他輸入類型
HTML5 為<input> 元素的 type 屬性又增加了幾個(gè)值≡凵福“email”搓幌、“url”是兩個(gè)得到支持最多的類型,各瀏覽器也都給他們?cè)黾恿硕ㄖ频尿?yàn)證機(jī)制迅箩。
<input type="email" name="email" />
<input type="url" name="homepage" />
"email" 類型要求輸入的文本必須符合電子郵件地址的模式溉愁,而"url"類型要求輸入的文本必須符合 URL 模式。
要檢查瀏覽器是否支持這些類型饲趋,可以在 JavaScript中創(chuàng)建一個(gè) <input>元素的type設(shè)置為其中一個(gè)拐揭,再檢測(cè)這個(gè)屬性的值
var input = document.createElement("input")
input.type = "email"
var isEmailSupported = (input.type == "email")
設(shè)置特定的輸入類型并不能阻止用戶輸入無效的值,只是應(yīng)用某些默認(rèn)的驗(yàn)證而已奕塑。
2.4.3堂污、數(shù)值范圍
除了上訴兩個(gè)之外,HTML5 還定義了另外幾個(gè)輸入元素龄砰。這幾個(gè)元素都要求填寫某種基于數(shù)字的值:number盟猖、range、datetime换棚、datetime-local式镐、date、month固蚤、week碟案、time
對(duì)所有這些數(shù)值類型的輸入元素,可以指定 min 屬性(最小的可能值)颇蜡、max屬性(最大的可能值)价说、step(兩個(gè)刻度之間的差值)。想讓用戶只能輸入0到100的值风秤,而且這個(gè)值必須是5的倍數(shù)鳖目,可以這些代碼:
<input type="number" min="0" max="100" step="5" name="count" />
在不同的瀏覽器中,可能會(huì)也可能不會(huì)看到能夠自動(dòng)遞增和遞減的數(shù)值調(diào)節(jié)按鈕(向上和向下按鈕)
2.4.4缤弦、輸入模式
HTML5 為文本字段新增了 pattern 屬性领迈。這個(gè)屬性的值是一個(gè)正則表達(dá)式,用于匹配文本框中的值。
例如:只允許在文本空中輸入數(shù)值
<input type="text" pattern="\d+" name="count" />
注意狸捅,模式的開頭和末尾不用加 ^ 和 $符號(hào)(假定已經(jīng)有了)衷蜓。這兩個(gè)符號(hào)表示輸入的值必須從頭到尾與模式匹配。
與其他輸入類型相似尘喝,指定 pattern 也不能阻止用戶輸入無效的文本磁浇。這個(gè)模式應(yīng)用給值窘问,瀏覽器來判斷值是有效竟稳,還是無效。
在JavaScript中可以通過 pattern 屬性訪問
var pattern = document.forms[0].elements['count'].pattern
使用以下代碼可以檢測(cè)瀏覽器是否支持 pattern 屬性
var isPatternSupported = "pattern" in document.createElement("input")
2.4.5边涕、檢測(cè)有效性
使用 checkValidity() 方法可以檢測(cè)表單中的某個(gè)字段是否有效缔赠。所有表單字段都有這個(gè)方法衍锚,如果字段的值有效,這個(gè)方法返回 true嗤堰,否則返回false戴质。字段的值是否有效的判斷依據(jù)是本節(jié)前面介紹過的那些約束。
if (document.forms[0].elements[0].checkValidity()) {
// 字段有效
} else {
// 字段無效
}
要檢測(cè)整個(gè)表單是否有效踢匣,可以在表單自身調(diào)用 checkValidity() 方法置森。如果所有表單字段都有效,這個(gè)方法返回 true符糊;即使有一個(gè)字段無效,這個(gè)方法也返回false
if (document.form[0].checkValidity()) {
// 表單有效
} else {
// 表單無效
}
與 checkValidity() 方法簡單地告訴你字段是否有效相比呛凶,validity 屬性則會(huì)告訴你為什么字段有效或無效男娄。這個(gè)對(duì)象中包含一系列屬性,每個(gè)屬性會(huì)返回一個(gè) 布爾值漾稀。
- customError:如果設(shè)置了 setCustomValidity()模闲,則返回 true,否則返回 false崭捍。
- patternMismatch:如果值與指定的pattern 屬性不匹配尸折,返回 true
- rangeOverflow:如果值比max值大,返回 true
- rangeUnderflow:如果值比 min 值小殷蛇,則返回 true
- stepMisMatch:如果 min 和 max 之間的步長值不合理实夹,返回true
- tooLong:如果值的長度超過了 maxlength 屬性指定的長度,返回 true粒梦。有的瀏覽器(如Firefox4)會(huì)自動(dòng)約束字符數(shù)量亮航,因此這個(gè)值可能永遠(yuǎn)返回 false
- typeMismatch:如果值不是"mail" 或 "url" 要求的格式,返回 true
- valid:如果這里的其他屬性都是false匀们,返回true缴淋。cjeckValidity() 也要求相同的值。
- valueMissing:如果標(biāo)注為 required 的字段中沒有值,則返回 true重抖。
因此露氮,要想得到更具體的信息,就應(yīng)該使用 validity 屬性來檢測(cè)表單的有效性钟沛。
if (input.validity.valueMissing) {
alert('please specify a value')
} else if (inout.validity.typeMismatch) {
alert('please enter an email address.')
} else {
alert('value is invalid')
}
2.4.6畔规、禁用驗(yàn)證
通過設(shè)置 novalidate 屬性,可以告訴表單不進(jìn)行驗(yàn)證讹剔。
<form method="post" action="signup.php" novalidate>
</form>
在 JavaScript中使用 noValidate 屬性可以去的或設(shè)置這個(gè)值油讯,如果這個(gè)屬性存在,值為 true
如果不存在延欠,值為 false陌兑。
document.forms[0].noValidate = true // 禁用表單
如果一個(gè)表單中有多個(gè)提交按鈕,為了指定點(diǎn)擊某個(gè)提交按鈕不必驗(yàn)證表單由捎,可以在相應(yīng)的按鈕上添加 formnovalidate 屬性
<form method="post" action="signup.php">
<input type="submit" value="submit" />
<input type="submit" value="Non-validating Submit" formnovalidate />
</form>
三兔综、選擇框腳本
選擇框是通過<select>、<option> 元素創(chuàng)建的狞玛。為了方便與這個(gè)控件交互软驰,除了所有表單字段共有的屬性和方法外,HTMLSelectElement 類型還提供了下列屬性和方法心肪。
- add(newOption, relOption):向控件中插入 新<option> 元素锭亏,其位置在相關(guān)項(xiàng)(relOption)之前。
- multiple:布爾值硬鞍,表示是否允許多項(xiàng)選擇慧瘤;等介于HTML中的 multiple 特性
- options:控件中所有 <option>元素的 HTMLCollection
- remove(index):移除給定位置的選項(xiàng)
- selectedIndex:基于0的選項(xiàng)中的索引,如果沒有選中項(xiàng)固该,則值為 -1锅减。對(duì)于支持多選的控件,只保存選中項(xiàng)中第一項(xiàng)的索引值伐坏。
- size:選擇框中可見的行數(shù)怔匣;等價(jià)于HTML 中的 size特性
選擇框的 type 屬性 不是 "select-one",就是"select-mutiple"桦沉,這取決于 HTML中有沒有 multiple 特性每瞒。選擇框的 value 屬性由當(dāng)前選中項(xiàng)決定,相應(yīng)規(guī)則如下:
- 如果沒有選中的項(xiàng)纯露,則選擇框的 value 屬性保存空字符串
- 如果有一個(gè)選中項(xiàng)独泞,而且該項(xiàng)的 value 特性已經(jīng)在 HTML 中指定,則選擇框的 value 屬性等于選中項(xiàng)的 value 特定苔埋。即使 value 特性的值是空字符串懦砂,也同樣遵循此條規(guī)則
- 如果有一個(gè)選中項(xiàng),但該項(xiàng)的 value 特性在HTML 中未指定,則選擇框的 value 屬性等于該項(xiàng)的文本
- 如果有多個(gè)選中項(xiàng)荞膘,則選擇框的 value 屬性將依據(jù)前兩條規(guī)則取得第一個(gè)選中項(xiàng)的值罚随。
<select name="locaation" id="selLocation">
<option value="Sunnyvale, CA">Sunnyvale</option>
<option value="">Chine</option>
<option>Australia</option>
</select>
如上DOM結(jié)構(gòu):
- 如果用戶選中了第一項(xiàng)那么值就是 Sunnyvale, CA
- 如果用戶選中了第二項(xiàng)羽资,則選擇框的值是 空字符串
- 如果選中第三個(gè)淘菩,則選擇框的值是 Austraila
在DOM中,每個(gè)<option>元素都有一個(gè) HTMLOptionElement 對(duì)象表示屠升,以便于訪問數(shù)據(jù)潮改,HTMLOptionElement對(duì)象添加了下列屬性:
- index:當(dāng)前選項(xiàng)在 options 集合中的索引
- label:當(dāng)前選項(xiàng)的標(biāo)簽;等價(jià)于 HTML 中的 label 特性
- selected:布爾值腹暖,表示當(dāng)前選項(xiàng)是否被選中汇在。將這個(gè)屬性設(shè)置為 true 可以選中當(dāng)前選項(xiàng)
- text:選項(xiàng)的文本。
- value:選項(xiàng)的值(等價(jià)于HTML中的value 特性)
大部分屬性的目的脏答,都是為了方便對(duì)選項(xiàng)數(shù)據(jù)的訪問糕殉。
var selectbox = document.forms[0].elements['location']
var text = selectbox.options[0].text
var value = selectbox.options[0].value
選擇框的 change 事件 與其他表單字段的 change 事件觸發(fā)的條件不一樣。其他表單字段的 change 事件是在值被修改且焦點(diǎn)離開當(dāng)前字段時(shí)觸發(fā)殖告,而選擇寬的 change 事件只要選中了選項(xiàng)就會(huì)觸發(fā)阿蝶。
3.1、選擇選項(xiàng)
對(duì)于只允許選擇一項(xiàng)的選擇框黄绩,訪問選中項(xiàng)的最簡單方式羡洁,就是使用選擇框的 selectedIndex 屬性,
var selectedOption = selectbox.options[selectbox.selectedIndex]
獲取后可以像下面這樣顯示該選項(xiàng)的信息
var selectbox = document.forms[0].elements[0]
var selectedIndex = selectbox.selectedIndex
var selectedOption = selectbox.options[selectedIndex]
var selectedValue = selectedOption.value
對(duì)于 可以選擇多項(xiàng)的選擇框爽丹,selectedIndex 屬性就好像只允許選擇一項(xiàng)一樣筑煮。設(shè)置selectedIndex 會(huì)導(dǎo)致取消以前的所有選項(xiàng)并選擇指定的那一項(xiàng),而讀取 selectedIndex 則只會(huì)返回選擇第一項(xiàng)的索引值习劫。
另一種選擇選項(xiàng)的方式,就是去的對(duì)某一項(xiàng)的引用嚼隘,然后將其 selected 屬性設(shè)置為 true诽里。
selectbox.options[0].selected = true
設(shè)置選項(xiàng)的selected 屬性,不會(huì)取消對(duì)其他選中項(xiàng)的選擇飞蛹,因而可以動(dòng)態(tài)選中任意多個(gè)項(xiàng)谤狡。需要注意的是,將selected 屬性設(shè)置為 false對(duì)單選選擇框沒有影響
實(shí)際上卧檐,selected屬性的作用主要是確定用戶選擇了選擇框中的哪一項(xiàng)墓懂。要取得所有選中項(xiàng),可以循環(huán)遍歷選項(xiàng)集合霉囚,然后測(cè)試每個(gè)選項(xiàng)的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) {
return.push(option)
}
}
return result;
}
下面是使用getSelectedOptions() 函數(shù)取得選中項(xiàng)的實(shí)例捕仔。
var selectbox = document.getElementById('selLocation')
var selectedOptions = getSelectedOptions(selectbox)
var message = ''
for(var i = 0, len = selectedOptions.length; i < len; i++) {
message += 'selectedIndex:' + selectedOptions[i].index + '\nSelected value:' + selectedOptions[i].value
}
console.log(message)
3.2、添加選項(xiàng)
可以使用 JavaScript 動(dòng)態(tài)創(chuàng)建選項(xiàng),并將它們添加到選擇框中榜跌。
第一種方式就是使用如下所示的DOM方法
var newOption = document.createElement('option')
newOption.appendChild(document.createTextNode('option tex'))
newOption.setAttribute('value', 'option value')
selectbox.appendChild(newOption)
第二種方式是使用 Option 構(gòu)造函數(shù)來創(chuàng)建新選項(xiàng)闪唆,構(gòu)造函數(shù)接受兩個(gè)參數(shù):文本(text)、值(value)
var newOption = new Option('Option text', 'Option value')
selectbox.appendChild(newOption) // 在 IE8 及指甲鉗版本中有問題
第三種方式是使用 選擇框的 add() 方法钓葫,接受兩個(gè)參數(shù):要添加的新選項(xiàng)悄蕾、將位于新選項(xiàng)之后的選項(xiàng)。如果想在最后添加一個(gè)選項(xiàng)础浮,第二個(gè)參數(shù)設(shè)置為 null帆调;在IE對(duì) add() 方法的實(shí)現(xiàn)中,第二個(gè)參數(shù)是可選的豆同,如果指定番刊,該參數(shù)必須是新選項(xiàng)之后的選項(xiàng)的索引。兼容DOM的瀏要求必須指定第二個(gè)參數(shù)诱告,因此如果要編寫跨瀏覽器代碼撵枢,需要為第二個(gè)參數(shù)傳入 undefined,即可精居。
var newOption = new Option('option text', 'option value')
selectbox.add(newOPtion, undefined) // 最佳方案
3.3锄禽、移除選項(xiàng)
與添加選項(xiàng)類似,移除選項(xiàng)的方式也有很多種
- 使用 removeChild() 的方法
selectbox.removeChild(selectbox,options[0]) // 移除第一個(gè)選項(xiàng)
- 使用選擇框的 remove() 方法靴姿。這個(gè)方法接受一個(gè)參數(shù)沃但,即要移除選項(xiàng)的索引
selectbox.remove(0) // 移除第一個(gè)選項(xiàng)
- 將相應(yīng)選項(xiàng)設(shè)置為 null。(這種方式也是 DOM 之前瀏覽器的遺留機(jī)制)
selectbox.options[0] = null // 移除第一個(gè)選項(xiàng)
要移除選擇框中所有的項(xiàng)佛吓,可以迭代所有選項(xiàng)并移除它們
function clearSelectbox(selectbox) {
for (var i = 0, len = selectbox.options.length; i < len; i++) {
selectbox.remove(0)
}
}
3.4宵晚、移動(dòng)和重排選項(xiàng)
在DOM標(biāo)準(zhǔn)出現(xiàn)之前,將一個(gè)選擇框中的選項(xiàng)移動(dòng)到另一個(gè)選擇框中是非常麻煩的维雇。使用DOM的appendChild() 方法淤刃,就可以將第一個(gè)選擇框中的選項(xiàng)直接移動(dòng)到第二個(gè)選擇框中。如果為 appendChild() 方法傳入一個(gè)文檔中已有的元素吱型,那么就會(huì)先從該元素的父節(jié)點(diǎn)中移除它逸贾,再把它添加到指定的位置。
var selectbox1 = document.getElementById('selLocations1')
var selectbox2 = document.getElementById('selLocations2')
selectbox2.appendChild(selectbox1.options[0])
移動(dòng)選項(xiàng)與移除選項(xiàng)有一個(gè)共同之處津滞,即會(huì)重置每一個(gè)選項(xiàng)的 index 屬性
重排 選項(xiàng)次序的過程也十分類似铝侵,要將選擇框中的某一項(xiàng)移動(dòng)到特定位置,最合適的 DOM 方法就是 insertBefore()触徐;appendChild() 方法只適用于將選項(xiàng)添加到選擇框的最后咪鲜。
在選擇框中向前移動(dòng)一個(gè)選項(xiàng)的位置
var optionToMove = selectbox.options[1]
selectbox.insertBefore(optionToMove, selectbox.options[optionToMove.index-1]
將選擇框中的選項(xiàng)向后移動(dòng)一個(gè)位置
selectbox.insertBefore(optionToMove, selectbox.options[optionToMove.index+2])
四、序列化表單
隨著 Ajax 的出現(xiàn)撞鹉,表單序列化已經(jīng)成為一種常見需求疟丙。在JavaScript中颖侄,可以利用表單字段的 type 屬性,連同name 和 value 屬性一起實(shí)現(xiàn)對(duì)表單的序列化隆敢。
在表單提交期間发皿,瀏覽器是怎樣將數(shù)據(jù)發(fā)給服務(wù)器的
- 對(duì)表單字段的名稱和值進(jìn)行 URL 編碼,使用 和號(hào)(&) 分隔拂蝎。
- 不發(fā)送禁用的表單字段
- 只發(fā)送勾選的復(fù)選框和單選按鈕
- 不發(fā)送 type 為 "reset" 和 "button" 的按鈕
- 多選選擇框中的每一個(gè)選中的值單獨(dú)一個(gè)條目
- 在單擊按鈕提交表單的情況下穴墅,也會(huì)發(fā)送提交按鈕;否則温自,不發(fā)送提交按鈕玄货。也包括 type 為 "image" 的 <input> 元素
- <select> 元素的值,就是選中 <option> 元素的 value 特性的值悼泌。如果 <option> 元素沒有 value特性松捉,則是 <option>元素的文本值
在表單序列化過程中,一般不包括任何按鈕字段馆里,因?yàn)榻Y(jié)果字符串很可能是通過其它方式提交的隘世。除此之外的其他上訴規(guī)則都應(yīng)該遵循。
// 表單序列化
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) { // 如果有 name 屬性 并且 有值
for (j = 0, optLen = field.options.length; j < optLen; j++) { // 遍歷 所有 option
option = field.options[j]
if (option.selected) { // 如果當(dāng)前選項(xiàng)被 選擇
optValue = ''
if (option.hasAttribute) { // 如果支持 hasAttribute() 方法
optValue = (option.hasAttribute('value') ? option.value : option.text) // 查找是否存在 value 屬性
} else { // 不支持 hasAttribute()
optValue = (option.attributes['value'].specified ? option.value : option.text) // 查明是否已規(guī)定 value 屬性
}
parts.push(encodeURIComponent(field.name) + '=' + encodeURIComponent(optValue))
}
}
}
break;
case undefined: // 字段集
case 'file': // 文件輸入
case 'submit': // 提交按鈕
case 'reset': // 重置按鈕
case 'button': // 自掉頭按鈕
break;
case 'radio': // 單選按鈕
case 'checkbox': // 復(fù)選框
if (!field.checked) {
break;
}
default: // 默認(rèn)操作
if (field.name.length) { // 不包含沒有 name 的表單字段
parts.push(encodeURIComponent(field.name) + '=' + encodeURIComponent(field.value))
}
}
}
return parts.join('&')
}
以下是這個(gè) 方法的簡單使用
<form action="www.xxx.xxx" id="myForm">
地區(qū):<select name="locaation" id="selLocation">
<option value="Sunnyvale, CA">Sunnyvale</option>
<option value="Chine">Chine</option>
<option value="Ireland">Ireland</option>
<option>Asutralia</option>
</select>
<p>用戶名:<input type="text" name="username"></p>
<p>郵箱:<input type="email" name="email"></p>
<p><input type="submit" value="submit"></p>
</form>
<script>
var form = document.forms[0]
form.onsubmit = function(event) {
event.preventDefault()
var fieldsStr = serialize(form)
console.log(fieldsStr)
}
</script>
五鸠踪、富文本編輯
富文本編輯丙者,又稱為 WYSIWYG(What You See Is What You Get,所見即所得)营密。在網(wǎng)頁中編輯富文本內(nèi)容械媒,是人本對(duì)web應(yīng)用程序最大的期待之一。這一技術(shù)的本質(zhì)评汰,就是在頁面中嵌入一個(gè)包含空HTML的頁面 iframe纷捞。通過設(shè)置 designMode 屬性,這個(gè)空白的 HTML 頁面可以被編輯被去,而編輯對(duì)象則是該頁面 <body> 元素的 HTML 代碼主儡。designMode 屬性有兩個(gè)可能的值:"off"(默認(rèn)值)和 "on"。在設(shè)置為 "on" 時(shí)惨缆,整個(gè)文檔都會(huì)變得可以編輯
可以給 iframe 指定一個(gè) 非常簡單的HTML 頁面作為其內(nèi)容來源糜值。
<!DOCTYPE>
<html>
<head>
<title> Black Page for Rich Text Editing</title>
</head>
<body></body>
</html>
在包含頁面中,需要使用 onload 事件處理程序來在恰當(dāng)?shù)臅r(shí)刻設(shè)置 designMode踪央, 如下:
<iframe name="richedit" style="width: 100px; height: 100px;" src="./blank.html"></iframe>
<script>
window.onload = function() {
frames['richedit'].document.designMode = 'on'
}
</script>
需要注意的是臀玄,不能以文件方式在本地直接用瀏覽器打開的瓢阴,地址欄是file:///畅蹂。可以試著在本地架設(shè)服務(wù)器來調(diào)試
5.1荣恐、使用 contenteditable 屬性
另一種編輯富文本內(nèi)容的方式是使用名為 contenteditable 的特殊屬性液斜,這個(gè)屬性也是由 IE 最早實(shí)現(xiàn)的累贤。可以吧 contenteditable 屬性應(yīng)用給頁面中的任何元素少漆,然后用戶立即就可以編輯該元素臼膏。這種方法之所以受到歡迎,是因?yàn)樗恍枰?iframe示损、空白頁 和 JavaScript 渗磅,只要為元素設(shè)置 contenteditable屬性即可
<div class="editable" id="richedit" contenteditable></div>
如上,元素中包含的任何文本內(nèi)容就都可以編輯了检访,就好像這個(gè)元素變成了 <textarea> 元素一樣始鱼。通過在這個(gè)元素上設(shè)置 contenteditable 元素,也能開打或關(guān)閉編輯模式
var div = document.getElementById('richedit')
div.contentEditable = true
div.contentEditable = false
contenteditable 屬性有三個(gè)可能的值:"true"表示打開脆贵,"false"表示關(guān)閉医清,"inherit"表示從父元素那里繼承
5.2、操作富文本
與富文本編輯器交互的主要方式卖氨,就是使用 document.execCommand()会烙。這個(gè)方法可以對(duì)文檔指向預(yù)定義的命令,而且可以應(yīng)用大多格式筒捺。這個(gè)方法接受三個(gè)參數(shù):
- 要執(zhí)行的命令名稱
- 表示瀏覽器是否應(yīng)該為當(dāng)前命令提供用戶界面的一個(gè)布爾值
- 指向命令必須的一個(gè)值(如果不需要值柏腻,則傳遞 null)
為了確保跨瀏覽器的兼容性焙矛,第二個(gè)參數(shù)應(yīng)該始終設(shè)置為 false葫盼,因?yàn)?Firefox 會(huì)在改參數(shù)為 true時(shí) 拋出錯(cuò)誤
不同瀏覽器支持的預(yù)定義命令也不一樣。下表列出了那些被支持最多的命令
命令 | 值(第三個(gè)參數(shù)) | 說明 |
---|---|---|
backcolor | 顏色字符串 | 設(shè)置文檔的背景顏色 |
bold | null | 將選擇的文本轉(zhuǎn)換為粗體 |
copy | null | 將選擇的文本復(fù)制到剪貼板 |
createlink | URL字符串 | 將選擇的文本轉(zhuǎn)換成一個(gè)鏈接村斟,指向指定的URL |
cut | null | 將選擇的文本剪切到剪貼板 |
delete | null | 刪除選擇的文本 |
fontname | 字體名稱 | 將選擇的文本修改為指定字體 |
fontsize | 1~7 | 將選擇的文本修改為指定字體大小 |
forecolor | 顏色字符串 | 將選擇的文本修改為指定的顏色 |
formatblock | 要包圍當(dāng)前文本的HTML標(biāo)簽贫导;如<h1> | 使用指定的HTML標(biāo)簽來格式化選擇的文本快 |
indent | null | 縮進(jìn)文本 |
inserthorizontalrule | null | 在插入字符處插入一個(gè)<hr>元素 |
insertimage | 圖像的URL | 在插入字符處插入一個(gè)圖像 |
insertorderedlist | null | 在插入字符處插入一個(gè)<ol>元素 |
insertunorderedlist | null | 在擦汗如字符處插入一個(gè)<ul>元素 |
insertparagraph | null | 在插入字符處插入一個(gè)<p>元素 |
italic | null | 將選擇的文本轉(zhuǎn)換成斜體 |
justifycenter | null | 將插入光標(biāo)所在文本塊居中對(duì)齊 |
justifyleft | null | 將插入光標(biāo)所在文本快左對(duì)齊 |
outden | null | 凸排文本(減少縮進(jìn)) |
paste | null | 將剪貼板中的文本粘貼到選擇的文本 |
removeformat | null | 移除插入光標(biāo)所在文本塊的塊級(jí)格式。這是撤銷 formatblock 命令的操作 |
selectall | null | 選擇文檔中的所有文本 |
underline | null | 為選擇的文本添加下劃線 |
unlink | null | 移除文本的鏈接蟆盹。這是冊(cè)小 createlink的命令的操作 |
其中孩灯,與剪貼板有關(guān)的命令在不同瀏覽器中的差異極大。Opera 根本沒有實(shí)現(xiàn)任何剪貼板命令逾滥,即使不能通過 document.execCommand() 來執(zhí)行這些命令峰档,但卻可以通過相應(yīng)的快捷鍵來實(shí)現(xiàn)同樣的操作。
使用上訴屬性寨昙,來簡單實(shí)現(xiàn)一個(gè)富文本
<button id="boldBtn">bold </button>
<button id="italicBtn">italic</button>
<button id="linkBtn">a</button>
<button id="h1Btn">H1</button>
<iframe name="richedit" style="width: 1000px; height: 300px;display: block" src="blank.html"></iframe>
<script>
window.onload = function() {
frames['richedit'].document.designMode = 'on'
document.getElementById('boldBtn').onclick = function() {
frames['richedit'].document.execCommand('bold', false, null)
}
document.getElementById('italicBtn').onclick = function() {
frames['richedit'].document.execCommand('italic', false, null)
}
document.getElementById('linkBtn').onclick = function() {
frames['richedit'].document.execCommand('createlink', false, 'http://www.baidu.com') // 默認(rèn)地址讥巡,簡單模擬
}
document.getElementById('h1Btn').onclick = function() {
frames['richedit'].document.execCommand('formatblock', false, '<h1>')
}
}
</script>
選區(qū)文本后,點(diǎn)擊不同的快捷鍵舔哪,實(shí)現(xiàn)修改外觀
同樣的方法也適用于頁面中 contenteditable 屬性為 "true" 的區(qū)塊欢顷,只要把對(duì)框架的引用替換成當(dāng)前窗口的 document 對(duì)象即可。
<div style="width: 1000px; height: 300px;display: block;border: 1px solid violet" id="div" contenteditable>
</div>
<script>
window.onload = function() {
document.getElementById('boldBtn').onclick = function() {
document.execCommand('bold', false, null)
}
document.getElementById('italicBtn').onclick = function() {
document.execCommand('italic', false, null)
}
document.getElementById('linkBtn').onclick = function() {
document.execCommand('createlink', false, 'http://www.baidu.com') // 默認(rèn)地址捉蚤,簡單模擬
}
document.getElementById('h1Btn').onclick = function() {
document.execCommand('formatblock', false, '<h1>')
}
}
需要注意的是抬驴,雖然所有瀏覽器都支持這些命令炼七,但這些命令所產(chǎn)生的 HTML 仍然有很大不同。由于各個(gè)瀏覽器實(shí)現(xiàn)命令的方式不同布持,加上它們通過 innerHTML 實(shí)現(xiàn)轉(zhuǎn)換的方式也不一樣豌拙,因此不能指望富文本編輯器會(huì)產(chǎn)生一致的 HTML。
除了命令之外题暖,還有一些于命令相關(guān)的方法
-
queryCommandEnabled()
用來檢測(cè)是否可以爭(zhēng)對(duì)當(dāng)前選擇的文本按傅,或者當(dāng)前插入字符所在位置執(zhí)行某個(gè)命令。接受一個(gè)參數(shù)胧卤,即要檢測(cè)的命令逞敷。如果當(dāng)前編輯區(qū)域允許執(zhí)行傳入的命令,這個(gè)方法返回 true灌侣,否則返回 false推捐。
var result = frames['richedit'].document.queryCommandEnabled('bold')
如果能夠?qū)Ξ?dāng)前選擇的文本執(zhí)行"bold"命令,以上代碼就會(huì)返回 ture
-
queryCommandState()
方法用于確定是否已將指定命令應(yīng)用到了選擇的文本侧啼。
var isBold = frames['richedit'].document.queryCommandState('bold')
如果以前已經(jīng)對(duì)選擇的文本執(zhí)行了"bold"命令牛柒,那么上面的代碼會(huì)返回 ture。
-
queryCommandValue()
用于取得執(zhí)行命令時(shí)傳入的值(即前面例子中傳給document.execCommand() 第三個(gè)參數(shù)
var fontSize = frames['richedit'].document.queryCommandValue('fontsize')
通過這個(gè)方法可以確定某個(gè)命令是怎樣應(yīng)用到選擇的文本的痊乾,可以據(jù)以確定在對(duì)其應(yīng)用后續(xù)命令是否合適
5.3皮壁、富文本選區(qū)
在富文本編輯器中,適用 框架(iframe)的getSelection() 方法哪审,可以確定實(shí)際選擇的文本蛾魄。這個(gè)方法是 window 對(duì)象和 document對(duì)象的屬性,調(diào)用它會(huì)返回一個(gè)表示當(dāng)前選擇文本的 Selection 對(duì)象湿滓。每個(gè)Selection對(duì)象都有下列屬性滴须。
- anchorNode:選區(qū)起點(diǎn)所在的節(jié)點(diǎn)。
- anchorOffset:在到達(dá)選區(qū)起點(diǎn)之前跳過的 anchorNode 中的字符數(shù)量
- focusNode:選區(qū)終點(diǎn)所在的節(jié)點(diǎn)
- focusOffset:focusNode中包含在選區(qū)之內(nèi)的字符數(shù)量叽奥。
- isCollapsed:布爾值扔水,表示選區(qū)的起點(diǎn)和終點(diǎn)是否重合
- rangeCount:選區(qū)中包含的DOM范圍的數(shù)量
Selection 對(duì)象的這些這些屬性并沒有包含多少有用的信息。下列方法提供了更多信息朝氓,并且支持對(duì)選區(qū)的操作
- addRange(range):將指定的DOM范圍添加到選區(qū)中
- collapse(node, offset):將選區(qū)折疊到指定節(jié)點(diǎn)中的相應(yīng)的文本偏移位置魔市。
- collapseToEnd():將選區(qū)折疊到終點(diǎn)
- collapseToStart():將選區(qū)折疊到起點(diǎn)位置
- **containsNode(node):確定指定的節(jié)點(diǎn)是否包含在候選區(qū)中
- deleteFromDocument():從文檔中刪除選區(qū)中的文本,document.execCommand('delete', false, null) 命令的結(jié)果相同
- extend(node, offset):將通過 focusNode赵哲、focusOffset 移動(dòng)到指定的位置來擴(kuò)展選區(qū)待德。
- getRangeAt(index):返回索引對(duì)應(yīng)的選區(qū)中的DOM范圍
- removeAllRanges():從選區(qū)中移除所有 DOM 范圍。實(shí)際上枫夺,這樣會(huì)移除選區(qū)将宪,因?yàn)檫x區(qū)中至少要有一個(gè)范圍
- **removeRange(range):從選區(qū)中移除指定的 DOM 范圍
- selectAllChildren(node):清除選區(qū)并選擇指定節(jié)點(diǎn)的所有子節(jié)點(diǎn)
- toString():返回選區(qū)所包含的文本內(nèi)容
Selection 對(duì)象的這些方法都極為使用,它們利用了 前面講到的 DOM范圍來管理選區(qū)。由于可以直接操作選擇文本的DOM表現(xiàn)涧偷,因此訪問DOM范圍與 使用 execCommand() 相比,能夠?qū)Ω晃谋揪庉嬈鬟M(jìn)行更加細(xì)化的控制毙死。
var selection = frames['richedit'].getSelection()
// 取得選擇的文本
var selectedText = selection.toString()
// 取得代表選區(qū)的范圍
var range = selection.getRangeAt(0)
// 突出顯示選擇的文本
var span = frames['richedit'].document.createElement('span')
span.style.backgroundColor = 'yellow'
range.surroundContents(span)
Firefox 3.6+ 中調(diào)用 document.getSelection() 會(huì)返回一個(gè)字符串燎潮。為此,可以在 Forefox 3.6+ 中該作調(diào)用 window.getSelection(), 從而范圍 selection 對(duì)象扼倘。Firefox 8修復(fù)了這個(gè)問題
IE8 及更早的版本不支持DOM范圍确封,但我們可以通過它支持的 selection 對(duì)象操作選擇的文本。要取得富文本編輯器中選擇的文本再菊,首先必須創(chuàng)建一個(gè)文本范圍爪喘,然后再像下面這樣訪問其 text 屬性。
var range = frames['richedit'].document.selection.createRange()
var selectedText = range.text
雖然使用 IE 的文本范圍來啊執(zhí)行 HTML 操作并不像使用 DOM 范圍那么可靠纠拔,但也不失為一種有效的途徑秉剑。要像前面使用 DOM 范圍那樣實(shí)現(xiàn)相同的文本高亮效果,可以組合使用 **htmlText **屬性和 pasteHTML() 方法
var range = frames['richedit'].document.selection.createRange()
range.pasteHTML('<span style="background-color: yellow">'+ range.htmlText + '</span>');
5.4稠诲、表單與富文本
富文本編輯器中的HTML不會(huì)被自動(dòng)提交給 服務(wù)器侦鹏,而需要我們手工來提交并提交HTML。為此臀叙,通陈运可以添加一個(gè)隱藏的表單字段,讓他的值等于 從 iframe 中提取的 HTML劝萤。
form.onsubmit = function() {
this.elements['comments'].value = frames['richedit'].document.body.innerHTML
}
對(duì)于 contenteditable 元素渊涝,也可以執(zhí)行類似的操作
form.onsubmit = function() {
this.elements['comments'].value = document.getElementById('richedit').innerHTML
}
六、小結(jié)
使用 JavaScript 可以增強(qiáng)已有的表單字段床嫌,從而創(chuàng)造出新的功能跨释,或者提升表單的易用性。
- 可以使用一些標(biāo)準(zhǔn) 或 非標(biāo)準(zhǔn)的方法選擇文本框的全部或部分文本
- 在文本框的內(nèi)容變化時(shí)厌处,可以通過偵聽鍵盤事件以及檢測(cè)插入的字符煤傍,來允許或禁止用戶輸入
- 除了Opera 其他主流瀏覽器都允許 通過 JavaScript 訪問 剪貼板中的數(shù)據(jù)。
- IE允許在任何時(shí)候訪問剪貼板的相關(guān)信息嘱蛋,而其他瀏覽器只能按在發(fā)生剪貼板事件時(shí)才能訪問蚯姆。
富文本編輯功能是通過一個(gè)包含空 HTML 文檔的 iframe 元素
來實(shí)現(xiàn)。通過將空文檔的 designMode 屬性設(shè)置為 'on'洒敏,就可以將頁面轉(zhuǎn)換為 可以編輯狀態(tài)龄恋,此時(shí)其表現(xiàn)如同字處理軟件。另外凶伙,也可以將某個(gè)元素設(shè)置為 contenteditable
郭毕。在默認(rèn)情況下,可以將字體加粗或者將文本轉(zhuǎn)換為斜體函荣,還可以使用剪貼板显押。
JavaScript通過使用 execCommand() 方法也可以實(shí)現(xiàn)相同的一些功能扳肛。另外,使用 queryCommandEnabled()乘碑、queryCommandState()挖息、queryCommandValue() 方法則可以取得有關(guān)文本選區(qū)的信息。由于以這種方式構(gòu)建的富文本編輯器并不是一個(gè)表單字段兽肤,因此在將其內(nèi)容提交給服務(wù)器之前套腹,必須將 iframe 或 contenteditable 元素中的 HTML 復(fù)制到一個(gè)表單字段中。