99re热这里只有精品视频,7777色鬼xxxx欧美色妇,国产成人精品一区二三区在线观看,内射爽无广熟女亚洲,精品人妻av一区二区三区

Javascript 聚焦:focus/blur

2023-02-17 10:55 更新

當(dāng)用戶點(diǎn)擊某個(gè)元素或使用鍵盤上的 ?Tab? 鍵選中時(shí),該元素將會(huì)獲得聚焦(focus)。還有一個(gè) HTML 特性(attribute)?autofocus? 可以讓焦點(diǎn)在網(wǎng)頁加載時(shí)默認(rèn)落在一個(gè)元素上,此外還有其它途徑可以獲得焦點(diǎn)。

聚焦到一個(gè)元素通常意味著:“準(zhǔn)備在此處接受數(shù)據(jù)”,所以,這正是我們可以運(yùn)行代碼以初始化所需功能的時(shí)刻。

失去焦點(diǎn)的時(shí)刻(“blur”)可能更為重要。它可能發(fā)生在用戶點(diǎn)擊頁面的其它地方,或者按下 Tab 鍵跳轉(zhuǎn)到下一個(gè)表單字段,亦或是其它途徑的時(shí)候。

失去焦點(diǎn)通常意味著:“數(shù)據(jù)已經(jīng)輸入完成”,所以我們可以運(yùn)行代碼來檢查它,甚至可以將其保存到服務(wù)器上,或進(jìn)行其他操作。

當(dāng)處理焦點(diǎn)事件時(shí),有一些重要的特性。我們將盡力把這些內(nèi)容介紹完整。

focus/blur 事件

當(dāng)元素聚焦時(shí),會(huì)觸發(fā) focus 事件,當(dāng)元素失去焦點(diǎn)時(shí),會(huì)觸發(fā) blur 事件。

讓我們使用它們來校驗(yàn)一個(gè) input 字段。

在下面這個(gè)示例中:

  • ?blur? 事件處理程序檢查這個(gè)字段是否輸入了電子郵箱,如果沒有輸入,則顯示一個(gè) error。
  • ?focus? 事件處理程序隱藏 error 信息(在 ?blur? 事件處理程序上會(huì)被再檢查一遍):
<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" 指示,因?yàn)橛脩粝胍匦螺斎胍恍﹥?nèi)容
    this.classList.remove('invalid');
    error.innerHTML = "";
  }
};
</script>

現(xiàn)代 HTML 允許我們使用 input 特性(attribute)進(jìn)行許多驗(yàn)證:requiredpattern 等。有時(shí)它們正是我們所需要的。當(dāng)我們需要更大的靈活性時(shí),可以使用 JavaScript。如果數(shù)據(jù)是正確的,我們可以把它自動(dòng)發(fā)送到服務(wù)器。

focus/blur 方法

elem.focus() 和 elem.blur() 方法可以設(shè)置和移除元素上的焦點(diǎn)。

例如,如果輸入值無效,我們可以讓焦點(diǎn)無法離開這個(gè) 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");
      // ...將焦點(diǎn)放回來
      input.focus();
    } else {
      this.classList.remove("error");
    }
  };
</script>

這段代碼在除了火狐(bug)之外的瀏覽器上都可以正常工作。

如果我們?cè)?nbsp;input 中輸入一些內(nèi)容,然后嘗試使用 Tab 鍵或點(diǎn)擊遠(yuǎn)離 <input> 的位置,那么 onblur 事件處理程序會(huì)把焦點(diǎn)重新設(shè)置到這個(gè) input 字段上。

請(qǐng)注意,我們無法通過在 onblur 事件處理程序中調(diào)用 event.preventDefault() 來“阻止失去焦點(diǎn)”,因?yàn)?nbsp;onblur 事件處理程序是在元素失去焦點(diǎn) 之后 運(yùn)行的。

但在實(shí)際中,在實(shí)現(xiàn)這樣的功能之前應(yīng)該認(rèn)真考慮一下,因?yàn)槲覀兺ǔ?nbsp;應(yīng)該將報(bào)錯(cuò)展示給用戶,但 不應(yīng)該阻止用戶在填寫我們的表單時(shí)的進(jìn)度。用戶可能會(huì)想先填寫其他表單項(xiàng)。

JavaScript 導(dǎo)致的焦點(diǎn)丟失

很多種原因可以導(dǎo)致焦點(diǎn)丟失。

其中之一就是用戶點(diǎn)擊了其它位置。當(dāng)然 JavaScript 自身也可能導(dǎo)致焦點(diǎn)丟失,例如:

  • 一個(gè) ?alert? 會(huì)將焦點(diǎn)移至自身,因此會(huì)導(dǎo)致元素失去焦點(diǎn)(觸發(fā) ?blur? 事件),而當(dāng) ?alert? 對(duì)話框被取消時(shí),焦點(diǎn)又會(huì)重新回到原元素上(觸發(fā) ?focus? 事件)。
  • 如果一個(gè)元素被從 DOM 中移除,那么也會(huì)導(dǎo)致焦點(diǎn)丟失。如果稍后它被重新插入到 DOM,焦點(diǎn)也不會(huì)回到它身上。

這些特性有時(shí)候會(huì)導(dǎo)致 focus/blur 處理程序發(fā)生異常 —— 在不需要它們時(shí)觸發(fā)。

最好的秘訣就是在使用這些事件時(shí)小心點(diǎn)。如果我們想要跟蹤用戶導(dǎo)致的焦點(diǎn)丟失,則應(yīng)該避免自己造成的焦點(diǎn)丟失。

允許在任何元素上聚焦:tabindex

默認(rèn)情況下,很多元素不支持聚焦。

列表(list)在不同的瀏覽器表現(xiàn)不同,但有一件事總是正確的:focus/blur 保證支持那些用戶可以交互的元素:<button><input>,<select>,<a> 等。

另一方面,為了格式化某些東西而存在的元素像 <div>,<span> 和 <table> —— 默認(rèn)是不能被聚焦的。elem.focus() 方法不適用于它們,并且 focus/blur 事件也絕不會(huì)被觸發(fā)。

使用 HTML-特性(attribute)tabindex 可以改變這種情況。

任何具有 tabindex 特性的元素,都會(huì)變成可聚焦的。該特性的 value 是當(dāng)使用 Tab(或類似的東西)在元素之間進(jìn)行切換時(shí),元素的順序號(hào)。

也就是說:如果我們有兩個(gè)元素,第一個(gè)具有 tabindex="1",第二個(gè)具有 tabindex="2",然后當(dāng)焦點(diǎn)在第一個(gè)元素的時(shí)候,按下 Tab 鍵,會(huì)使焦點(diǎn)移動(dòng)到第二個(gè)元素身上。

切換順序?yàn)椋簭?nbsp;1 開始的具有 tabindex 的元素排在前面(按 tabindex 順序),然后是不具有 tabindex 的元素(例如常規(guī)的 <input>)。

不具有 tabindex 的元素按文檔源順序(默認(rèn)順序)切換。

這里有兩個(gè)特殊的值:

  • ?tabindex="0"? 會(huì)使該元素被與那些不具有 ?tabindex? 的元素放在一起。也就是說,當(dāng)我們切換元素時(shí),具有 ?tabindex="0"? 的元素將排在那些具有 ?tabindex ≥ 1? 的元素的后面。
  • 通常,它用于使元素具有焦點(diǎn),但是保留默認(rèn)的切換順序。使元素成為與 ?<input>? 一樣的表單的一部分。

  • ?tabindex="-1"? 只允許以編程的方式聚焦于元素。?Tab? 鍵會(huì)忽略這樣的元素,但是 ?elem.focus()? 有效。

舉個(gè)例子,這里有一個(gè)列表。點(diǎn)擊第一項(xiàng),然后按 Tab 鍵:

點(diǎn)擊第一項(xiàng),然后按 Tab 鍵。跟蹤順序。請(qǐng)注意,多按幾次 Tab 鍵后,會(huì)將焦點(diǎn)移到這個(gè)通過 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 委托

focus 和 blur 事件不會(huì)向上冒泡。

例如,我們不能把 onfocus 放在 <form> 上來對(duì)其進(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>

上面這個(gè)示例并不工作,因?yàn)楫?dāng)用戶聚焦于 <input> 時(shí),focus 事件只會(huì)在該 <input> 上觸發(fā)。它不會(huì)向上冒泡。所以 form.onfocus 永遠(yuǎn)不會(huì)觸發(fā)。

這里有兩個(gè)解決方案。

方案一,有一個(gè)遺留下來的有趣的特性(feature):focus/blur 不會(huì)向上冒泡,但會(huì)在捕獲階段向下傳播。

這樣可以生效:

<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>
  // 將處理程序置于捕獲階段(最后一個(gè)參數(shù)為 true)
  form.addEventListener("focus", () => form.classList.add('focused'), true);
  form.addEventListener("blur", () => form.classList.remove('focused'), true);
</script>

方案二,可以使用 focusin 和 focusout 事件 —— 與 focus/blur 事件完全一樣,只是它們會(huì)冒泡。

值得注意的是,必須使用 elem.addEventListener 來分配它們,而不是 on<event>。

所以,這是另一個(gè)可行的變體:

<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>

總結(jié)

在元素獲得/失去焦點(diǎn)時(shí)會(huì)觸發(fā) focus 和 blur 事件。

它們的特點(diǎn)是:

  • 它們不會(huì)冒泡。但是可以改為在捕獲階段觸發(fā),或者使用 ?focusin/focusout?。
  • 大多數(shù)元素默認(rèn)不支持聚焦。使用 ?tabindex? 可以使任何元素變成可聚焦的。

可以通過 document.activeElement 來獲取當(dāng)前所聚焦的元素。

任務(wù)


可編輯的 div

重要程度: 5

創(chuàng)建一個(gè) <div>,它在被點(diǎn)擊后變成 <textarea>。

文本區(qū)域(textarea)允許我們編輯 <div> 里的 HTML。

當(dāng)用戶按下 Enter 鍵,或者 <textarea> 失去焦點(diǎn)時(shí),<textarea> 會(huì)變回 <div>,并且 <textarea> 中的內(nèi)容會(huì)變成 <div> 中的 HTML。

在新窗口中演示

打開一個(gè)任務(wù)沙箱。


解決方案

使用沙箱打開解決方案。


點(diǎn)擊即可編輯單元格

重要程度: 5

使單元格在點(diǎn)擊時(shí)可編輯。

  • 點(diǎn)擊時(shí) —— 單元格應(yīng)該變成“可編輯的”(在里面會(huì)出現(xiàn)文本區(qū)域),我們修改其中的 HTML。在這不調(diào)整單元格大小,所有幾何形狀保持不變。
  • OK 和 CANCEL 按鈕會(huì)出現(xiàn)在單元格的下面,用以完成/取消編輯。
  • 同一時(shí)刻只有一個(gè)單元格可被編輯。當(dāng)一個(gè) ?<td>? 處于“編輯模式”時(shí),在其它單元格上的點(diǎn)擊會(huì)被忽略。
  • 該表格可能有很多單元格。請(qǐng)使用事件委托。

打開一個(gè)任務(wù)沙箱。


解決方案

  1. 在點(diǎn)擊時(shí) —— 用相同尺寸且無邊框的 ?<textarea>? 替換單元格的 ?innerHTML?。可以使用 JavaScript 或 CSS 設(shè)置正確的尺寸。
  2. 將 ?textarea.value? 設(shè)置為 ?td.innerHTML?。
  3. 聚焦在文本區(qū)域(textarea)。
  4. 在單元格下方應(yīng)該顯示 OK/CANCEL 按鈕,并處理對(duì)它們的點(diǎn)擊事件。

使用沙箱打開解決方案。


鍵盤移動(dòng)老鼠

重要程度: 4

聚焦在老鼠上。然后使用鍵盤的方向鍵移動(dòng)它:

在新窗口中演示

P.S. 除了 #mouse 元素外,不要在任何地方放置事件處理程序。

P.P.S. 不要修改 HTML/CSS,這個(gè)方法應(yīng)該是通用的,可以用于任何元素。

打開一個(gè)任務(wù)沙箱。


解決方案

我們可以使用 mouse.onclick 來處理點(diǎn)擊,并將老鼠設(shè)置為 position:fixed,然后使用 mouse.onkeydown 來處理鍵盤的方向鍵。

唯一的缺陷是 keydown 僅會(huì)在聚焦的元素上觸發(fā)。因此,我們需要向元素添加 tabindex。因?yàn)槲覀兘垢?HTML,所以我們可以使用 mouse.tabIndex 屬性。

P.S. 我們也可以使用 mouse.onfocus 代替 mouse.onclick。

使用沙箱打開解決方案。


以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)