8 个你不知道的 DOM 功能
翻譯:瘋狂的技術宅
原文:blog.logrocket.com/8-dom-featu…
未經許可嚴禁轉載!
最近關注了太多的工具,現(xiàn)在最好從所有 React 和 npm-install-everything 的文章中休息一下,來看看一些純粹的 DOM 和 Web API 功能,它們可以在不依賴任何第三方庫的前提下在現(xiàn)代瀏覽器中運行。
這篇文章將講解八個鮮為人知的 DOM 功能,這些功能具有強大的瀏覽器支持。為了幫助你理解每個功能的工作原理,我將通過大量的測試代碼為你自己提供演示,這些代碼都放在了CodePen上。
學習這些方法和屬性沒有陡峭的學習曲線,并且可以與項目中所使用的任何工具集在一起使用。
addEventListener() 的新參數(shù) options
你肯定用 addEventListener() 處理過將事件附加到 Web 文檔中的元素。通常 addEventListener() 調用看起來像這樣:
element.addEventListener('click', doSomething, false); 復制代碼第一個參數(shù)是正在監(jiān)聽的事件。第二個參數(shù)是一個回調函數(shù),它將在事件發(fā)生時執(zhí)行。第三個參數(shù)是一個名為 useCapture 的布爾值,用于指示是否要使用事件冒泡或捕獲。
這些大家都知道(特別是前兩個)。但也許你不知道 addEventListener() 也接受一個替換最終布爾值的參數(shù)。這個新參數(shù)是一個 options 對象,如下所示:
element.addEventListener('click', doSomething, {capture: false,once: true,passive: false }); 復制代碼請注意,該語法允許定義三個不同的屬性。以下是每個含義的快速概述:
- capture ?—?與之前提到的 useCapture 參數(shù)相同的布爾值
- once ?— 布爾值,如果設置為 true,則表示該事件應僅在目標元素上運行一次,然后被刪除
- passive ?—?一個最終的布爾值,如果設置為 true,表示該函數(shù)永遠不會調用 preventDefault(),即使它被包含在函數(shù)體中
其中最有趣的是 once 選項。這肯定會在很多情況下派上用場,并且無需用 removeEventListener() 或使用其他一些復雜的技術來強制單個事件觸發(fā)器。如果你用過 jQuery,可能熟悉該庫中的類似功能:.one() 方法。
你可以試著運行以下 CodePen 項目中關于 options 對象的一些代碼:
See the Pen Using addEventListener() with an `options` Object as Third Parameter by Louis Lazaris (@impressivewebs) on CodePen.CodePen演示:codepen.io/impressivew…
請注意,演示頁面上的按鈕只會附加一次文本。如果將 once 值改為 false,則多次單擊該按鈕,每次單擊按鈕時都會附加文本。
瀏覽器對 options 對象的支持非常好:所有瀏覽器都支持它,除了 IE11 及更早版本,因此如果你不考慮微軟 Edge 之前的瀏覽器,那么使用起來還是非常安全的。
scrollTo() 方法用于在窗口或元素中平滑滾動
平滑滾動總是經常被用到的。當點擊本地頁面鏈接并立即跳轉到指定位置時(如果你眨眼,甚至可能會錯過跳轉過程),這會顯得很突兀。平滑滾動改進了頁面的用戶體驗。
雖然過去用 jQuery 插件就足以完成了,但現(xiàn)在用 window.scrollTo() 方法只需要一行 JavaScript。
scrollTo() 方法作用于 Window 對象,告訴瀏覽器滾動到頁面上的指定位置。這是一個最簡單語法的例子:
window.scrollTo(0, 1000); 復制代碼這將向右滾動窗口 0px (表示x坐標或水平滾動)并向下滾動 1000px (垂直滾動,這通常是你想要的)。但這樣做的話滾動并不是一個平滑的動畫效果,頁面將會突然滾動。
有時確實是你想要的。但是為了能夠平滑滾動,你必須加入鮮為人知的 ScrollToOptions 對象,如下所示:
window.scrollTo({top: 0,left: 1000,behavior: 'smooth' }); 復制代碼這段代碼與前面的例子相同,但在 options 對象中添加了 behavior 屬性的smooth值。
請看下面這個 CodePen 演示,允許你自定義滾動量和行為:
See the Pen Using addEventListener() with an `options` Object as Third Parameter by Louis Lazaris (@impressivewebs) on CodePen.CodePen演示:codepen.io/impressivew…
嘗試在框中輸入一個數(shù)字(最好是一個比較大的數(shù)字,比如4000)并更改 behavior 選擇框以使用 smooth 或 auto(這是 behavior 屬性僅有的兩個選項)。
關于此功能的一些說明:
-
對于 scrollTo() 的基本支持是全面的,但并非所有瀏覽器都支持 options 對象
-
此方法在應用于元素時也可以使用
-
這些選項也同樣適用于 scroll() 和 scrollBy() 方法
setTimeout() 和帶有可選參數(shù)的 setInterval()
在更多情況下,使用 window.setTimeout() 和 window.setInterval() 實現(xiàn)基于時序的動畫的方案已經被性能更好的 window.requestAnimationFrame() 所取代。但是有些情況下使用 setTimeout() 或 setInterval() 是正確的選擇,因此了解這些方法的一個鮮為人知的特性是很好的。
通常你總會看到這些方法被使用,語法如下:
let timer = window.setInterval(doSomething, 3000); function doSomething () {// Something happens here… } 復制代碼這里的 setInterval() 傳遞兩個參數(shù):回調函數(shù)和時間間隔。如果使用 setTimeout() 將只運行一次,而在當前這種情況下,它會無限期地運行,直到我在傳入 timer 變量時調用 window.clearTimeout()。
這很簡單。但是如果我希望回調函數(shù)能夠接受參數(shù)呢?可以這樣做:
let timer = window.setInterval(doSomething, 3000, 10, 20); function doSomething (a, b) {// Something happens here… } 復制代碼注意我在 setInterval() 調用中添加了兩個參數(shù)。然后我的 doSomething() 函數(shù)接受了這些參數(shù),并可以根據需要操作它們。
這是一個 CodePen 演示,演示了如何使用 setTimeout():
See the Pen Optional Parameters with window.setTimeout() by Louis Lazaris (@impressivewebs) on CodePen.CodePen:codepen.io/impressivew…
單擊該按鈕時,將會使用傳入的兩個值進行計算。可以通過修改代碼中的數(shù)字更改值。
至于瀏覽器支持,似乎在兼容性上有些小問題,不過看上去現(xiàn)在幾乎所有還在使用中的瀏覽器都支持可選參數(shù)功能,包括 IE10。
單選按鈕和復選框的 defaultChecked 屬性
你可能知道,對于單選按鈕和復選框,可以直接通過 checked 屬性去獲取或設置它,如下所示(假設 radioButton 是對特定表單輸入的引用):
console.log(radioButton.checked); // true radioButton.checked = false; console.log(radioButton.checked); // false 復制代碼但是還有一個名為 defaultChecked 的屬性,它可以應用于單選按鈕組或復選框組,用來找出組中哪一個最初被設置為了 checked。
這是一些HTML示例:
<form id="form"><input type="radio" value="one" name="setOne"> One<input type="radio" value="two" name="setOne" checked> Two<br /><input type="radio" value="three" name="setOne"> Three </form> 復制代碼有了這個屬性,即使在更改了被選中的單選按鈕之后,也可以通過遍歷找出最初哪一個是默認值,如下所示:
for (i of myForm.setOne) {if (i.defaultChecked === true) {console.log(‘i.value’);} } 復制代碼下面是CodePen演示,它將顯示當前選中的單選按鈕或默認選中的單選按鈕,具體取決于你所使用的按鈕:
See the Pen defaultChecked on Radio Buttons by Louis Lazaris (@impressivewebs) on CodePen.CodePen:codepen.io/impressivew…
該示例中的 defaultChecked 選項將始終為 “Two” 單選按鈕。如上所述,這也可以用于復選框組。你可以試著修改 HTML 中的默認選中選項,然后再次點擊按鈕看看效果。
下面是一個復選框組的演示:
See the Pen defaultChecked on Checkboxes by Louis Lazaris (@impressivewebs) on CodePen.CodePen:codepen.io/impressivew…
在這種情況下,你會注意到默認情況下應該會檢查兩個復選框,因此當使用 defaultChecked 查詢時,這兩個復選框都會返回 true。
使用 normalize() 和 wholeText 操作文本節(jié)點
HTML 文檔中的文本節(jié)點可能會很復雜,尤其是當動態(tài)插入或創(chuàng)建節(jié)點時。例如假設有以下 HTML:
<p id="el">This is the initial text.</p> 復制代碼然后我可以在該段落元素中添加一個文本節(jié)點:
let el = document.getElementById('el'); el.appendChild(document.createTextNode(' Some more text.')); console.log(el.childNodes.length); // 2 復制代碼請注意,在附加的文本節(jié)點之后的注釋中,我記錄了段落內子節(jié)點的長度,并且它表示有兩個節(jié)點。這些節(jié)點是一個文本字符串,但由于文本是動態(tài)附加的,因此它們應該被視為單獨的節(jié)點。
在某些情況下,如果將文本視為單個文本節(jié)點會更有幫助,這使文本更容易操作。這就是 normalize()和wholeText()的用武之地。
normalize() 方法可用于合并單獨的文本節(jié)點:
el.normalize(); console.log(el.childNodes.length); // 1 復制代碼在元素上調用 normalize() 將會合并該元素內的任何相鄰的文本節(jié)點。如果恰好在相鄰的文本節(jié)點之間散布著一些 HTML,那么 HTML 將保持原樣,而所有相鄰的文本節(jié)點將被合并。
但是,如果由于某種原因我想使文本節(jié)點分開,但我仍然希望能夠將文本作為一個單元抓取,那么 wholeText 就是有用的。因此我可以在相鄰的文本節(jié)點上執(zhí)行此操作,而不是調用 normalize()。
console.log(el.childNodes[0].wholeText); // This is the initial text. Some more text. console.log(el.childNodes.length); // 2 復制代碼只要我沒有調用 normalize(),文本節(jié)點的長度將保持為 2,我可以用 wholeText 記錄整個文本。但需要注意以下幾點:
- 我必須在其中一個文本節(jié)點上調用 wholeText,而不是元素(因此代碼中的el.childNodes [0]、el.childNodes[1]也可以正常工作)
- 文本節(jié)點必須相鄰,中間不能有其他 HTML 分隔它們
你可以看到這兩個功能以及 splitText() 方法已經用在了這個 CodePen 演示中。打開 CodePen 控制臺或瀏覽器的開發(fā)人員工具控制臺可以查看生成的日志。
insertAdjacentElement() 和 insertAdjacentText()
很多人可能很熟悉 insertAdjacentHTML() 方法,它允許你輕松地將一串文本或 HTML 添加到頁面中與其他元素相關的特定位置。
但也許你不知道的是,還有另外兩個以類似方式工作的方法:insertAdjacentElement() 和 insertAdjacentText()。
insertAdjacentHTML() 的一個缺點是插入的內容必須是字符串的形式。因此如果要包含 HTML,則必須將其聲明為:
el.insertAdjacentHTML('beforebegin', '<p><b>Some example</b> text goes here.</p>'); 復制代碼但是 insertAdjacentElement() 的第二個參數(shù)可以是元素引用:
let el = document.getElementById('example'), addEl = document.getElementById('other'); el.insertAdjacentElement('beforebegin', addEl); 復制代碼這個方法的有趣之處在于,它不僅會將引用的元素添加到指定的位置,而且還會將元素從文檔中的原始位置移除。這是一種在 DOM 中移動元素的簡單方法。
這是使用 insertAdjacentElement()的 CodePen 演示。點擊按鈕可以有效地“移動”目標元素:
CodePen:codepen.io/impressivew…
See the Pen Using insertAdjacentElement() to Change an Element's Location by Louis Lazaris (@impressivewebs) on CodePen.insertAdjacentText()方法的工作方式類似,但提供的文本字符串將僅作為文本插入,即使它包含HTML。請注意以下演示:
CodePen:codepen.io/impressivew…
See the Pen Using insertAdjacentText() with HTML Tags by Louis Lazaris (@impressivewebs) on CodePen.你可以將自己的文本添加到輸入字段,然后使用該按鈕將其添加到文檔中。注意:任何特殊字符(如HTML標記)都將會作為 HTML 實體插入,請區(qū)分此方法與 insertAdjacentHTML() 行為的區(qū)別。
所有三種方法(insertAdjacentHTML(),insertAdjacentElement()和insertAdjacentText() )的第一個參數(shù)所使用的值的規(guī)則是相同的:
- beforebegin:在調用方法的元素之前插入
- afterbegin:在第一個子節(jié)點之前插入元素內部
- beforeend:在最后一個子節(jié)點之后插入元素內部
- afterend:插入到元素后面
event.detail 屬性
如前所述,我們可以用熟悉的 addEventListener()方法將事件附加到網頁上的元素。例如:
btn.addEventListener('click', function () {// do something here... }, false); 復制代碼使用addEventListener()時,你可能想要阻止函數(shù)調用中的默認瀏覽器行為。例如,你可能希望攔截 <a> 元素的點擊并使用 JavaScript 來處理,你會這樣做:
btn.addEventListener('click', function (e) {// do something here...e.preventDefault(); }, false); 復制代碼這里使用了 preventDefault(),這等價于老式的 return false 語句。這需要你將 event 對象傳遞給函數(shù),因為在該對象上調用了 preventDefault()方法。
但是你可以用 event 對象做更多事情。事實上當使用某些事件時(例如click,dbclick,mouseup,mousedown),這些事件會暴露一些叫做 UIEvent 接口的東西。正如 MDN 所指出的,該接口上的許多功能已被棄用或沒有標準化。但最有趣并且最有用的是 detail 屬性,它是官方規(guī)范的一部分。
以下是它在同一個事件監(jiān)聽器示例中的代碼:
btn.addEventListener('click', function (e) {// do something here...console.log(e.detail); }, false); 復制代碼我已經設置了一個 CodePen 演示,演示了使用許多不同事件的結果:
CodePen:codepen.io/impressivew…
See the Pen Using the event.detail Property by Louis Lazaris (@impressivewebs) on CodePen.演示中的每個按鈕都將按照按鈕文本描述的方式進行響應,并顯示一條顯示當前點擊次數(shù)的消息。需要注意的是:
- WebKit 瀏覽器允許無限制的點擊次數(shù),除了 dblclick,它總是兩次點擊。 Firefox 只允許最多三次點擊,然后計數(shù)再次開始
- 我已經包通過包含 blur 和 focus 來證明這些不符合條件并且總是返回0(即沒有點擊)
- 在 IE11 等舊版瀏覽器中的行為嚴重不一致
請注意,在演示中包含了一個很好的用例——模仿三擊事件:
btnT.addEventListener('click', function (e) {if (e.detail === 3) {trpl.value = 'Triple Click Successful!';} }, false); 復制代碼如果所有瀏覽器都計算過三次點擊次數(shù),那么你還可以檢測到更高的點擊次數(shù),但我認為在大多數(shù)情況下,三次點擊事件就足夠了。
scrollHeight 和 scrollWidth 屬性
scrollHeight 和 scrollWidth 屬性可能聽起來很熟悉,因為你可能會將它們與其他與寬度和高度相關的 DOM 功能混淆。例如,offsetWidth 和 offsetHeight 屬性將返回元素的高度和寬度,而不會考慮溢出。
請注意以下演示:
CodePen:codepen.io/impressivew…
See the Pen offsetHeight Doesn't Count Past CSS Overflow by Louis Lazaris (@impressivewebs) on CodePen.演示中的列具有相同的內容。左邊列的 overflow 被設置為 auto,而右邊列的 overflow 被設置為 hidden。 offsetHeight 屬性返回相同的值,因為它不考慮可滾動區(qū)域或隱藏區(qū)域,它只測量元素的實際高度,包括垂直填充和邊框。
另一方面,命名恰當?shù)?scrollHeight 屬性將會計算元素的完整高度,包括可滾動(或隱藏)區(qū)域:
CodePen:codepen.io/impressivew…
See the Pen scrollHeight Measures an Element's Full Scrollable Area by Louis Lazaris (@impressivewebs) on CodePen.上面的演示與前一個相同,只不過它用了 scrollHeight 來獲取每列的高度。再次注意,兩列的值相同。但這次它的值要打得多,因為溢出區(qū)域也算作高度的一部分。
上面的示例主要關注元素高度,這是最常見的用例,但你也可以用 offsetWidth 和 scrollWidth,它們以相同的方式應用于水平滾動。
總結
這就是你不知道的 DOM 功能列表,這些可能是我在近幾年遇到的一些最有趣的功能,所以我希望在不遠的將來你能把它們用在自己的項目中。
如果你之前用過其中的某些功能,或是如果你能想到其中某個功能的有趣的用例,請在評論中告訴我。
歡迎關注前端公眾號:前端先鋒,獲取前端工程化使用工具包。
轉載于:https://juejin.im/post/5d07441de51d4510926a7b45
總結
以上是生活随笔為你收集整理的8 个你不知道的 DOM 功能的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: quora
- 下一篇: img 加载 svg占位符_SVG组件可