原文:blog.logrocket.com/8-dom-featu…
做者:Louis Lazaris
翻譯:前端小白javascript
這篇文章將考慮八個不爲人知的DOM特性,這些特性具備強大的瀏覽器支持。 爲了幫助解釋每一個工做原理,我會提供大量的交互式演示,同時也便於你本身嘗試html
這些方法和屬性沒有一個陡峭的學習曲線,能夠很好地配合你的項目所使用的任何工具集。前端
你確定已經使用過 addEventListener()
將事件附加到web文檔中的元素上。一般,addEventListener()
調用看起來是這樣的:java
element.addEventListener('click', doSomething, false);
複製代碼
第一個參數是我正在監聽的事件。第二個參數是一個回調函數,它將在事件發生時執行。第三個參數是一個名爲 useCapture
的布爾值,用於指示是否要使用事件冒泡或捕獲。jquery
這些都是衆所周知的(尤爲是前兩個)。可是,您可能不知道 addEventListener()
也接受將第三個布爾值類型的參數替換爲另外一個新參數。這個新參數是一個看起來像這樣的 options
對象:git
element.addEventListener('click', doSomething, {
capture: false,
once: true,
passive: false
});
複製代碼
注意,語法容許定義三個不一樣的屬性。下面是每一個詞的意思:github
useCapture
參數同樣true
, 表示事件只在目標元素上運行一次,而後被刪除true
, 表示函數不會調用 preventDefault()
, 即便它包含在函數體中這三個選項中最有趣的是 once
。這在不少狀況下都很是有用,能夠避免使用 removeEventListener()
或其餘複雜的技術來強制觸發單個事件。若是您曾經使用過jQuery,那麼您可能熟悉該庫中的相似特性.one()方法。web
您能夠在下面的codepen中嘗試使用options對象:npm
codepen: codepen.io/impressivew…api
注意演示頁面上的按鈕只會追加文本一次。若是將once值更改成false,而後屢次單擊該按鈕,則每次單擊按鈕時都會附加文本。
瀏覽器對options對象的支持很是友好:除了IE11和更早版本以外,全部瀏覽器都支持它,因此若是你不在意微軟Edge以前的瀏覽器,那麼使用它是很是安全的。
平滑滾動一直是須要的。當本地頁面連接當即跳轉到指定位置時(若是你眨眼,你甚至可能會錯過跳轉),這會讓人很不舒服。 平滑滾動改進了用戶頁面體驗。
雖然過去使用jQuery插件能夠實現,但如今可使用 window.scrollTo()
方法,只須要使用一行JavaScript代碼就能夠實現。
scrollTo()
方法應用於 window
對象,以告訴瀏覽器滾動到頁面上指定的位置。下面是一個基本語法的示例:
window.scrollTo(0, 1000);
複製代碼
這將使窗口向右滾動0px(表示x座標,或水平滾動),向下滾動1000px(垂直方向,這一般是您想要的)。但在這種狀況下,滾動將不會是一個平滑的動畫效果;頁面將忽然滾動,就像使用本地連接到指定哈希URL同樣。
雖然有時候這就是你想要的。可是爲了得到平滑的滾動,必須使用不多有人知道的 ScrollToOptions
對象,就像這樣:
window.scrollTo({
top: 0,
left: 1000,
behavior: 'smooth'
});
複製代碼
這段代碼與前面的示例相同,可是在 options
對象中添加了 behavior
屬性並將其值設爲 smooth
。
codepen: codepen.io/impressivew…
關於這個特性的一些注意事項:
scrollTo()
,但不是全部瀏覽器都支持 options
對象window
options
對象一樣適用於 scroll()
和 scrollBy()
在許多狀況下,使用 window.setTimeout()
和 window.setInterval()
執行基於時間的動畫如今已經被性能更友好的 window.requestAnimationFrame()
所取代。可是在某些狀況下,setTimeout()
或 setInterval()
是更好的的選擇,所以有必要了解其中不多有人知道的一些特性。
一般,你會看到使用他們的語法是這樣的:
let timer = window.setInterval(doSomething, 3000);
function doSomething () {
// Something happens here...
}
複製代碼
這裏 setInterval()
調用傳入兩個參數:回調函數和時間間隔。對於 setTimeout()
,它將運行一次,而在本例中,它將無限期地運行,直到我傳入計時器ID,調用 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
屬性,可使用 checked
屬性,以下所示(假設 radioButton
是對某個表單輸入的引用)
console.log(radioButton.checked); // true
radioButton.checked = false;
console.log(radioButton.checked); // false
複製代碼
但還有一個名爲 defaultChecked
的屬性,它能夠應用於單選按鈕或複選框組,來得到組中最初設置爲checked的元素是哪一個
<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>
複製代碼
有了這個,即便在更改了選中的單選按鈕以後,我也能夠遍歷單選框並找出初始爲checked是哪個,以下所示:
for (i of myForm.setOne) {
if (i.defaultChecked === true) {
console.log(‘i.value’);
}
}
複製代碼
下面是CodePen演示,它將顯示當前選中的單選框或默認選中的單選框,具體取決於你點擊哪一個按鈕:
codepen: codepen.io/impressivew…
該示例中的 defaultChecked
始終是單選框Two。如前所述,這也能夠經過複選框組來完成。嘗試更改HTML中的默認選中選項,而後再次嘗試點擊按鈕。
這是複選框組的演示: codepen: codepen.io/impressivew…
在本例中,你將注意到默認狀況下選中了兩個複選框,所以當使用 defaultChecked
查詢時,這兩個複選框都將返回 true
。
HTML文檔中的文本節點可能比較複雜,特別是在動態插入或建立節點時。例如,若是我有如下HTML
<p id="el">This is the initial text.</p>
複製代碼
我能夠給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]
)許多人可能熟悉 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…
insertAdjacentText()
方法的工做原理相似,可是所提供的文本字符串將僅做爲文本插入,即便它包含HTML。demo以下:
codepen: codepen.io/impressivew…
您能夠將本身的文本添加到輸入字段,而後使用按鈕將其添加到文檔中。注意,任何特殊字符(如HTML標記)都將做爲HTML實體插入,這與 insertAdjacentHTML()
方法的行爲不一樣。
insertAdjacentHTML()
, insertAdjacentElement()
, 和 insertAdjacentText()
的第一個參數相同,可取值爲:
當使用 addEventListener()
時,您可能須要防止函數調用中的默認瀏覽器行爲。例如,您可能想攔截 <a>
元素上的單擊,並使用JavaScript處理這些單擊。你會這樣作:
btn.addEventListener('click', function (e) {
// do something here...
e.preventDefault();
}, false);
複製代碼
preventDefault()
,和之前的 return false
效果是同樣的。這須要將事件對象傳遞到函數中,由於該對象會調用 preventDefault()
方法。
你還能夠利用那個事件對象作更多。實際上,當觸發某些事件(例如click、dbclick、mouseup、mousedown)時,他們會暴露出一個稱爲UIEvent接口。正如MDN所指出的,這個接口上的許多特性都被廢除了。但有用的是detail屬性,它是官方規範的一部分。
他看起來像這樣:
btn.addEventListener('click', function (e) {
// do something here...
console.log(e.detail);
}, false);
複製代碼
cedepen: codepen.io/impressivew…
演示中的每一個按鈕都將以按鈕文本描述的方式響應,並顯示一條顯示當前單擊次數的消息。須要注意的一些事情:
blur
和 focus
,來證實這些不符合條件,並將始終返回0(即沒有點擊)注意,演示中包含了一個很實用的技巧,能夠模擬三次單擊事件:
btnT.addEventListener('click', function (e) {
if (e.detail === 3) {
trpl.value = 'Triple Click Successful!';
}
}, false);
複製代碼
若是全部瀏覽器都計算過三次點擊次數,那麼您還能夠檢測到更高的點擊次數,但我認爲在大多數狀況下,三次點擊事件就足夠了。
scrollHeight
和 scrollWidth
屬性可能聽起來很熟悉,由於您可能會將它們與其餘與寬度和高度相關的DOM功能混淆。 例如,offsetWidth
和 offsetHeight
屬性將返回元素的高度或寬度,而不會考慮溢出。
參考下面demo:
codepen: codepen.io/impressivew…
演示中的列具備相同的內容。左邊列的 overflow
設置爲 auto
,右邊列的 overflow
設置爲 hidden
。offsetHeight
屬性爲每一個屬性返回相同的值,由於它不考慮可滾動區域或隱藏區域;它只測量元素的實際高度,包括任何垂直填充和邊框。
另外一方面,名稱恰當的 scrollHeight
屬性將計算元素的所有高度,包括可滾動(或隱藏)區域:
codepen: codepen.io/impressivew…
上面的演示與前面的演示相同,只是它使用了 scrollHeightto
獲取每一個列的高度。再次注意,這兩列的值是相同的。但這一次,它是一個更高的數字,由於溢出面積也被算做高度的一部分。
上面的示例主要關注元素高度,這是最多見的用例,但您也可使用 offsetWidth
和 scrollWidth
,它們將以相同的方式應用於水平滾動。
以上就是我列出的DOM特性,這些多是我在過去幾年遇到的最有趣的特性,因此我但願在不久的未來,您至少可以在項目中使用其中的一個特性。