翻譯:瘋狂的技術宅javascript
原文:blog.logrocket.com/8-dom-featu…html
未經許可嚴禁轉載!前端
最近關注了太多的工具,如今最好從全部 React 和 npm-install-everything 的文章中休息一下,來看看一些純粹的 DOM 和 Web API 功能,它們能夠在不依賴任何第三方庫的前提下在現代瀏覽器中運行。java
這篇文章將講解八個不爲人知的 DOM 功能,這些功能具備強大的瀏覽器支持。爲了幫助你理解每一個功能的工做原理,我將經過大量的測試代碼爲你本身提供演示,這些代碼都放在了CodePen上。jquery
學習這些方法和屬性沒有陡峭的學習曲線,而且能夠與項目中所使用的任何工具集在一塊兒使用。git
你確定用 addEventListener()
處理過將事件附加到 Web 文檔中的元素。一般 addEventListener()
調用看起來像這樣:github
element.addEventListener('click', doSomething, false);
複製代碼
第一個參數是正在監聽的事件。第二個參數是一個回調函數,它將在事件發生時執行。第三個參數是一個名爲 useCapture
的布爾值,用於指示是否要使用事件冒泡或捕獲。web
這些你們都知道(特別是前兩個)。但也許你不知道 addEventListener()
也接受一個替換最終布爾值的參數。這個新參數是一個 options
對象,以下所示:npm
element.addEventListener('click', doSomething, {
capture: false,
once: true,
passive: false
});
複製代碼
請注意,該語法容許定義三個不一樣的屬性。如下是每一個含義的快速概述:前端工程化
useCapture
參數相同的布爾值true
,則表示該事件應僅在目標元素上運行一次,而後被刪除true
,表示該函數永遠不會調用 preventDefault()
,即便它被包含在函數體中其中最有趣的是 once
選項。這確定會在不少狀況下派上用場,而且無需用 removeEventListener()
或使用其餘一些複雜的技術來強制單個事件觸發器。若是你用過 jQuery,可能熟悉該庫中的相似功能:.one() 方法。
你能夠試着運行如下 CodePen 項目中關於 options
對象的一些代碼:
CodePen演示:codepen.io/impressivew…
請注意,演示頁面上的按鈕只會附加一次文本。若是將 once
值改成 false
,則屢次單擊該按鈕,每次單擊按鈕時都會附加文本。
瀏覽器對 options
對象的支持很是好:全部瀏覽器都支持它,除了 IE11 及更早版本,所以若是你不考慮微軟 Edge 以前的瀏覽器,那麼使用起來仍是很是安全的。
平滑滾動老是常常被用到的。當點擊本地頁面連接並當即跳轉到指定位置時(若是你眨眼,甚至可能會錯過跳轉過程),這會顯得很突兀。平滑滾動改進了頁面的用戶體驗。
雖然過去用 jQuery 插件就足以完成了,但如今用 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…
嘗試在框中輸入一個數字(最好是一個比較大的數字,好比4000)並更改 behavior
選擇框以使用 smooth
或 auto
(這是 behavior
屬性僅有的兩個選項)。
關於此功能的一些說明:
對於 scrollTo()
的基本支持是全面的,但並不是全部瀏覽器都支持 options
對象
此方法在應用於元素時也可使用
這些選項也一樣適用於 scroll()
和 scrollBy()
方法
在更多狀況下,使用 window.setTimeout()
和 window.setInterval()
實現基於時序的動畫的方案已經被性能更好的 window.requestAnimationFrame()
所取代。可是有些狀況下使用 setTimeout()
或 setInterval()
是正確的選擇,所以瞭解這些方法的一個不爲人知的特性是很好的。
一般你總會看到這些方法被使用,語法以下:
let timer = window.setInterval(doSomething, 3000);
function doSomething () {
// Something happens here…
}
複製代碼
這裏的 setInterval()
傳遞兩個參數:回調函數和時間間隔。若是使用 setTimeout()
將只運行一次,而在當前這種狀況下,它會無限期地運行,直到我在傳入 timer 變量時調用 window.clearTimeout()
。
這很簡單。可是若是我但願回調函數可以接受參數呢?能夠這樣作:
let timer = window.setInterval(doSomething, 3000, 10, 20);
function doSomething (a, b) {
// Something happens here…
}
複製代碼
注意我在 setInterval()
調用中添加了兩個參數。而後個人 doSomething()
函數接受了這些參數,並能夠根據須要操做它們。
這是一個 CodePen 演示,演示瞭如何使用 setTimeout()
:
CodePen:codepen.io/impressivew…
單擊該按鈕時,將會使用傳入的兩個值進行計算。能夠經過修改代碼中的數字更改值。
至於瀏覽器支持,彷佛在兼容性上有些小問題,不過看上去如今幾乎全部還在使用中的瀏覽器都支持可選參數功能,包括 IE10。
你可能知道,對於單選按鈕和複選框,能夠直接經過 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
。
HTML 文檔中的文本節點可能會很複雜,尤爲是當動態插入或建立節點時。例如假設有如下 HTML:
<p id="el">This is the initial text.</p>
複製代碼
而後我能夠在該段落元素中添加一個文本節點:
let el = document.getElementById('el');
el.appendChild(document.createTextNode(' Some more text.'));
console.log(el.childNodes.length); // 2
複製代碼
請注意,在附加的文本節點以後的註釋中,我記錄了段落內子節點的長度,而且它表示有兩個節點。這些節點是一個文本字符串,但因爲文本是動態附加的,所以它們應該被視爲單獨的節點。
在某些狀況下,若是將文本視爲單個文本節點會更有幫助,這使文本更容易操做。這就是 normalize()
和wholeText()
的用武之地。
normalize()
方法可用於合併單獨的文本節點:
el.normalize();
console.log(el.childNodes.length); // 1
複製代碼
在元素上調用 normalize()
將會合並該元素內的任何相鄰的文本節點。若是剛好在相鄰的文本節點之間散佈着一些 HTML,那麼 HTML 將保持原樣,而全部相鄰的文本節點將被合併。
可是,若是因爲某種緣由我想使文本節點分開,但我仍然但願可以將文本做爲一個單元抓取,那麼 wholeText
就是有用的。所以我能夠在相鄰的文本節點上執行此操做,而不是調用 normalize()
。
console.log(el.childNodes[0].wholeText);
// This is the initial text. Some more text.
console.log(el.childNodes.length); // 2
複製代碼
只要我沒有調用 normalize()
,文本節點的長度將保持爲 2
,我能夠用 wholeText
記錄整個文本。但須要注意如下幾點:
wholeText
,而不是元素(所以代碼中的el.childNodes [0]
、el.childNodes[1]
也能夠正常工做)你能夠看到這兩個功能以及 splitText()
方法已經用在了這個 CodePen 演示中。打開 CodePen 控制檯或瀏覽器的開發人員工具控制檯能夠查看生成的日誌。
不少人可能很熟悉 insertAdjacentHTML()
方法,它容許你輕鬆地將一串文本或 HTML 添加到頁面中與其餘元素相關的特定位置。
但也許你不知道的是,還有另外兩個以相似方式工做的方法:insertAdjacentElement()
和 insertAdjacentText()
。
insertAdjacentHTML()
的一個缺點是插入的內容必須是字符串的形式。所以若是要包含 HTML,則必須將其聲明爲:
el.insertAdjacentHTML('beforebegin', '<p><b>Some example</b> text goes here.</p>');
複製代碼
可是 insertAdjacentElement()
的第二個參數能夠是元素引用:
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 實體插入,請區分此方法與 insertAdjacentHTML()
行爲的區別。
全部三種方法(insertAdjacentHTML()
,insertAdjacentElement()
和insertAdjacentText()
)的第一個參數所使用的值的規則是相同的:
beforebegin
:在調用方法的元素以前插入afterbegin
:在第一個子節點以前插入元素內部beforeend
:在最後一個子節點以後插入元素內部afterend
:插入到元素後面如前所述,咱們能夠用熟悉的 addEventListener()
方法將事件附加到網頁上的元素。例如:
btn.addEventListener('click', function () {
// do something here...
}, false);
複製代碼
使用addEventListener()
時,你可能想要阻止函數調用中的默認瀏覽器行爲。例如,你可能但願攔截 <a>
元素的點擊並使用 JavaScript 來處理,你會這樣作:
btn.addEventListener('click', function (e) {
// do something here...
e.preventDefault();
}, false);
複製代碼
這裏使用了 preventDefault()
,這等價於老式的 return false
語句。這須要你將 event
對象傳遞給函數,由於在該對象上調用了 preventDefault()
方法。
可是你能夠用 event
對象作更多事情。事實上當使用某些事件時(例如click
,dbclick
,mouseup
,mousedown
),這些事件會暴露一些叫作 UIEvent 接口的東西。正如 MDN 所指出的,該接口上的許多功能已被棄用或沒有標準化。但最有趣而且最有用的是 detail
屬性,它是官方規範的一部分。
如下是它在同一個事件監聽器示例中的代碼:
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.演示中的每一個按鈕都將按照按鈕文本描述的方式進行響應,並顯示一條顯示當前點擊次數的消息。須要注意的是:
dblclick
,它老是兩次點擊。 Firefox 只容許最多三次點擊,而後計數再次開始blur
和 focus
來證實這些不符合條件而且老是返回0(即沒有點擊)請注意,在演示中包含了一個很好的用例——模仿三擊事件:
btnT.addEventListener('click', function (e) {
if (e.detail === 3) {
trpl.value = 'Triple Click Successful!';
}
}, false);
複製代碼
若是全部瀏覽器都計算過三次點擊次數,那麼你還能夠檢測到更高的點擊次數,但我認爲在大多數狀況下,三次點擊事件就足夠了。
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
屬性返回相同的值,由於它不考慮可滾動區域或隱藏區域,它只測量元素的實際高度,包括垂直填充和邊框。
另外一方面,命名恰當的 scrollHeight
屬性將會計算元素的完整高度,包括可滾動(或隱藏)區域:
CodePen:codepen.io/impressivew…
See the Pen scrollHeight Measures an Element's Full Scrollable Area by Louis Lazaris ( @impressivewebs) on CodePen.上面的演示與前一個相同,只不過它用了 scrollHeight
來獲取每列的高度。再次注意,兩列的值相同。但此次它的值要打得多,由於溢出區域也算做高度的一部分。
上面的示例主要關注元素高度,這是最多見的用例,但你也能夠用 offsetWidth
和 scrollWidth
,它們以相同的方式應用於水平滾動。
這就是你不知道的 DOM 功能列表,這些多是我在近幾年遇到的一些最有趣的功能,因此我但願在不遠的未來你能把它們用在本身的項目中。
若是你以前用過其中的某些功能,或是若是你能想到其中某個功能的有趣的用例,請在評論中告訴我。