W3Cschool
恭喜您成為首批注冊用戶
獲得88經(jīng)驗值獎勵
當(dāng)用戶點擊某個元素或使用鍵盤上的 ?Tab
? 鍵選中時,該元素將會獲得聚焦(focus)。還有一個 HTML 特性(attribute)?autofocus
? 可以讓焦點在網(wǎng)頁加載時默認(rèn)落在一個元素上,此外還有其它途徑可以獲得焦點。
聚焦到一個元素通常意味著:“準(zhǔn)備在此處接受數(shù)據(jù)”,所以,這正是我們可以運(yùn)行代碼以初始化所需功能的時刻。
失去焦點的時刻(“blur”)可能更為重要。它可能發(fā)生在用戶點擊頁面的其它地方,或者按下 Tab 鍵跳轉(zhuǎn)到下一個表單字段,亦或是其它途徑的時候。
失去焦點通常意味著:“數(shù)據(jù)已經(jīng)輸入完成”,所以我們可以運(yùn)行代碼來檢查它,甚至可以將其保存到服務(wù)器上,或進(jìn)行其他操作。
當(dāng)處理焦點事件時,有一些重要的特性。我們將盡力把這些內(nèi)容介紹完整。
當(dāng)元素聚焦時,會觸發(fā) focus
事件,當(dāng)元素失去焦點時,會觸發(fā) blur
事件。
讓我們使用它們來校驗一個 input
字段。
在下面這個示例中:
blur
? 事件處理程序檢查這個字段是否輸入了電子郵箱,如果沒有輸入,則顯示一個 error。focus
? 事件處理程序隱藏 error 信息(在 ?blur
? 事件處理程序上會被再檢查一遍):<style>
.invalid { border-color: red; }
#error { color: red }
</style>
Your email please: <input type="email" id="input">
<div id="error"></div>
<script>
input.onblur = function() {
if (!input.value.includes('@')) { // not email
input.classList.add('invalid');
error.innerHTML = 'Please enter a correct email.'
}
};
input.onfocus = function() {
if (this.classList.contains('invalid')) {
// 移除 "error" 指示,因為用戶想要重新輸入一些內(nèi)容
this.classList.remove('invalid');
error.innerHTML = "";
}
};
</script>
現(xiàn)代 HTML 允許我們使用 input
特性(attribute)進(jìn)行許多驗證:required
,pattern
等。有時它們正是我們所需要的。當(dāng)我們需要更大的靈活性時,可以使用 JavaScript。如果數(shù)據(jù)是正確的,我們可以把它自動發(fā)送到服務(wù)器。
elem.focus()
和 elem.blur()
方法可以設(shè)置和移除元素上的焦點。
例如,如果輸入值無效,我們可以讓焦點無法離開這個 input
字段:
<style>
.error {
background: red;
}
</style>
Your email please: <input type="email" id="input">
<input type="text" style="width:220px" placeholder="make email invalid and try to focus here">
<script>
input.onblur = function() {
if (!this.value.includes('@')) { // not email
// 顯示 error
this.classList.add("error");
// ...將焦點放回來
input.focus();
} else {
this.classList.remove("error");
}
};
</script>
這段代碼在除了火狐(bug)之外的瀏覽器上都可以正常工作。
如果我們在 input
中輸入一些內(nèi)容,然后嘗試使用 Tab 鍵或點擊遠(yuǎn)離 <input>
的位置,那么 onblur
事件處理程序會把焦點重新設(shè)置到這個 input
字段上。
請注意,我們無法通過在 onblur
事件處理程序中調(diào)用 event.preventDefault()
來“阻止失去焦點”,因為 onblur
事件處理程序是在元素失去焦點 之后 運(yùn)行的。
但在實際中,在實現(xiàn)這樣的功能之前應(yīng)該認(rèn)真考慮一下,因為我們通常 應(yīng)該將報錯展示給用戶,但 不應(yīng)該阻止用戶在填寫我們的表單時的進(jìn)度。用戶可能會想先填寫其他表單項。
JavaScript 導(dǎo)致的焦點丟失
很多種原因可以導(dǎo)致焦點丟失。
其中之一就是用戶點擊了其它位置。當(dāng)然 JavaScript 自身也可能導(dǎo)致焦點丟失,例如:
- 一個 ?
alert
? 會將焦點移至自身,因此會導(dǎo)致元素失去焦點(觸發(fā) ?blur
? 事件),而當(dāng) ?alert
? 對話框被取消時,焦點又會重新回到原元素上(觸發(fā) ?focus
? 事件)。- 如果一個元素被從 DOM 中移除,那么也會導(dǎo)致焦點丟失。如果稍后它被重新插入到 DOM,焦點也不會回到它身上。
這些特性有時候會導(dǎo)致
focus/blur
處理程序發(fā)生異常 —— 在不需要它們時觸發(fā)。
最好的秘訣就是在使用這些事件時小心點。如果我們想要跟蹤用戶導(dǎo)致的焦點丟失,則應(yīng)該避免自己造成的焦點丟失。
默認(rèn)情況下,很多元素不支持聚焦。
列表(list)在不同的瀏覽器表現(xiàn)不同,但有一件事總是正確的:focus/blur
保證支持那些用戶可以交互的元素:<button>
,<input>
,<select>
,<a>
等。
另一方面,為了格式化某些東西而存在的元素像 <div>
,<span>
和 <table>
—— 默認(rèn)是不能被聚焦的。elem.focus()
方法不適用于它們,并且 focus/blur
事件也絕不會被觸發(fā)。
使用 HTML-特性(attribute)tabindex
可以改變這種情況。
任何具有 tabindex
特性的元素,都會變成可聚焦的。該特性的 value
是當(dāng)使用 Tab(或類似的東西)在元素之間進(jìn)行切換時,元素的順序號。
也就是說:如果我們有兩個元素,第一個具有 tabindex="1"
,第二個具有 tabindex="2"
,然后當(dāng)焦點在第一個元素的時候,按下 Tab 鍵,會使焦點移動到第二個元素身上。
切換順序為:從 1
開始的具有 tabindex
的元素排在前面(按 tabindex
順序),然后是不具有 tabindex
的元素(例如常規(guī)的 <input>
)。
不具有 tabindex
的元素按文檔源順序(默認(rèn)順序)切換。
這里有兩個特殊的值:
tabindex="0"
? 會使該元素被與那些不具有 ?tabindex
? 的元素放在一起。也就是說,當(dāng)我們切換元素時,具有 ?tabindex="0"
? 的元素將排在那些具有 ?tabindex ≥ 1
? 的元素的后面。通常,它用于使元素具有焦點,但是保留默認(rèn)的切換順序。使元素成為與 ?<input>
? 一樣的表單的一部分。
tabindex="-1"
? 只允許以編程的方式聚焦于元素。?Tab
? 鍵會忽略這樣的元素,但是 ?elem.focus()
? 有效。舉個例子,這里有一個列表。點擊第一項,然后按 Tab 鍵:
點擊第一項,然后按 Tab 鍵。跟蹤順序。請注意,多按幾次 Tab 鍵后,會將焦點移到這個通過 iframe 嵌入的示例的外面。
<ul>
<li tabindex="1">One</li>
<li tabindex="0">Zero</li>
<li tabindex="2">Two</li>
<li tabindex="-1">Minus one</li>
</ul>
<style>
li { cursor: pointer; }
:focus { outline: 1px dashed green; }
</style>
順序就像這樣:1 - 2 - 0
。通常,<li>
不支持聚焦,但 tabindex
可以使它能聚焦,使這成為可能,并且還帶有事件以及 :focus
樣式。
屬性 ?
elem.tabIndex
? 也有效我們可以使用
elem.tabIndex
通過 JavaScript 來添加tabindex
。效果是一樣的。
focus
和 blur
事件不會向上冒泡。
例如,我們不能把 onfocus
放在 <form>
上來對其進(jìn)行高亮,像這樣:
<!-- on focusing in the form -- add the class -->
<form onfocus="this.className='focused'">
<input type="text" name="name" value="Name">
<input type="text" name="surname" value="Surname">
</form>
<style> .focused { outline: 1px solid red; } </style>
上面這個示例并不工作,因為當(dāng)用戶聚焦于 <input>
時,focus
事件只會在該 <input>
上觸發(fā)。它不會向上冒泡。所以 form.onfocus
永遠(yuǎn)不會觸發(fā)。
這里有兩個解決方案。
方案一,有一個遺留下來的有趣的特性(feature):focus/blur
不會向上冒泡,但會在捕獲階段向下傳播。
這樣可以生效:
<form id="form">
<input type="text" name="name" value="Name">
<input type="text" name="surname" value="Surname">
</form>
<style> .focused { outline: 1px solid red; } </style>
<script>
// 將處理程序置于捕獲階段(最后一個參數(shù)為 true)
form.addEventListener("focus", () => form.classList.add('focused'), true);
form.addEventListener("blur", () => form.classList.remove('focused'), true);
</script>
方案二,可以使用 focusin
和 focusout
事件 —— 與 focus/blur
事件完全一樣,只是它們會冒泡。
值得注意的是,必須使用 elem.addEventListener
來分配它們,而不是 on<event>
。
所以,這是另一個可行的變體:
<form id="form">
<input type="text" name="name" value="Name">
<input type="text" name="surname" value="Surname">
</form>
<style> .focused { outline: 1px solid red; } </style>
<script>
form.addEventListener("focusin", () => form.classList.add('focused'));
form.addEventListener("focusout", () => form.classList.remove('focused'));
</script>
在元素獲得/失去焦點時會觸發(fā) focus
和 blur
事件。
它們的特點是:
focusin/focusout
?。tabindex
? 可以使任何元素變成可聚焦的。可以通過 document.activeElement
來獲取當(dāng)前所聚焦的元素。
創(chuàng)建一個 <div>
,它在被點擊后變成 <textarea>
。
文本區(qū)域(textarea)允許我們編輯 <div>
里的 HTML。
當(dāng)用戶按下 Enter 鍵,或者 <textarea>
失去焦點時,<textarea>
會變回 <div>
,并且 <textarea>
中的內(nèi)容會變成 <div>
中的 HTML。
使單元格在點擊時可編輯。
<td>
? 處于“編輯模式”時,在其它單元格上的點擊會被忽略。<textarea>
? 替換單元格的 ?innerHTML
???梢允褂?JavaScript 或 CSS 設(shè)置正確的尺寸。textarea.value
? 設(shè)置為 ?td.innerHTML
?。聚焦在老鼠上。然后使用鍵盤的方向鍵移動它:
P.S. 除了 #mouse
元素外,不要在任何地方放置事件處理程序。
P.P.S. 不要修改 HTML/CSS,這個方法應(yīng)該是通用的,可以用于任何元素。
我們可以使用 mouse.onclick
來處理點擊,并將老鼠設(shè)置為 position:fixed
,然后使用 mouse.onkeydown
來處理鍵盤的方向鍵。
唯一的缺陷是 keydown
僅會在聚焦的元素上觸發(fā)。因此,我們需要向元素添加 tabindex
。因為我們禁止更改 HTML,所以我們可以使用 mouse.tabIndex
屬性。
P.S. 我們也可以使用 mouse.onfocus
代替 mouse.onclick
。
Copyright©2021 w3cschool編程獅|閩ICP備15016281號-3|閩公網(wǎng)安備35020302033924號
違法和不良信息舉報電話:173-0602-2364|舉報郵箱:jubao@eeedong.com
掃描二維碼
下載編程獅App
編程獅公眾號
聯(lián)系方式:
更多建議: