P粉0088297912023-08-22 20:21:16
對於這個答案,我將querySelector
和querySelectorAll
稱為querySelector*,將getElementById
、getElementsByClassName
、getElementsByTagName
和getElementsByName
稱為getElement*。
這些資訊的許多資訊可以在規範中進行驗證,很多是我在寫時執行的各種基準測試得出的。規格:https://dom.spec.whatwg.org/
querySelector
和getElementById
都傳回單一元素。 querySelectorAll
和getElementsByName
都回傳NodeList。 getElementsByClassName
和getElementsByTagName
都回傳HTMLCollection。 NodeList和HTMLCollection都被稱為元素的集合。 這些概念在下表中總結。
Function | Live? | Type | Time Complexity querySelector | | Element | O(n) querySelectorAll | N | NodeList | O(n) getElementById | | Element | O(1) getElementsByClassName | Y | HTMLCollection | O(1) getElementsByTagName | Y | HTMLCollection | O(1) getElementsByName | Y | NodeList | O(1)
HTMLCollection不像NodeList那樣類似數組,不支援.forEach()。我發現擴展運算符對繞過這個問題很有用:
[...document.getElementsByClassName("someClass")].forEach()
每個元素和全域document
都可以存取所有這些函數,除了getElementById
和getElementsByName
,它們只在document
上實作。
鍊式使用getElement*呼叫而不是使用querySelector*將提高效能,特別是在非常大的DOM上。即使在小的DOM和/或非常長的鏈上,通常也更快。然而,除非您知道需要效能,否則應該優先選擇querySelector*的可讀性。 querySelectorAll
通常更難重寫,因為您必須在每個步驟中從NodeList或HTMLCollection中選擇元素。例如,以下程式碼不起作用:
document.getElementsByClassName("someClass").getElementsByTagName("div")
#因為您只能在單一元素上使用getElements*,而不是集合,但如果您只想要一個元素,那麼:
document.querySelector("#someId .someClass div")
#可以寫成:
document.getElementById("someId").getElementsByClassName("someClass")[0].getElementsByTagName("div")[0]
#注意在傳回集合的每個步驟中使用[0]
,以取得集合的第一個元素,最終結果只有一個元素,就像使用querySelector
一樣。
由於所有元素都可以使用querySelector*和getElement*調用,因此可以同時使用這兩個調用進行鍊式操作,這在您想要一些性能提升但無法避免使用無法用getElement*調用編寫的querySelector時非常有用。
儘管通常很容易判斷一個選擇器是否可以只使用getElement*呼叫來編寫,但有一種情況可能不明顯:
document.querySelectorAll(".class1.class2")
#可以重寫為
document.getElementsByClassName("class1 class2")
#在使用querySelector*獲取的靜態元素上使用getElement*將導致元素相對於querySelector複製的靜態DOM子集是動態的,但相對於完整文檔DOM是靜態的...這就是簡單的動態/靜態元素解釋開始分崩離析的地方。您應該盡量避免需要擔心這個問題的情況,但如果確實存在這種情況,請記住querySelector*呼叫在傳回引用之前會複製它們找到的元素,而getElement*呼叫則會直接取得引用而不複製。
querySelector*和getElementById
前序、深度優先的方式遍歷元素,在規範中稱為「樹順序」。對於其他getElement*調用,從規範中我無法確定它們是否與樹順序相同,但getElementsByClassName(".someClass")[0]
可能在每個瀏覽器中結果不可靠。 getElementById("#someId")
應該是可靠的,即使您的頁面上有多個相同的id副本。
當我在處理無限滾動頁面時,我不得不研究這個問題,我認為這可能是一個常見的情況,效能成為一個問題。我們的程式碼中有onScroll事件,其中包含querySelectorAll呼叫。即使呼叫被限制速率,如果您滾動到足夠遠的位置,頁面也會崩潰,此時將有太多調用迭代太多元素,瀏覽器無法跟上。 DOM的大小在這種用例中是相關的,因此在無限滾動頁面上運行的程式碼中,更傾向於使用getElement*呼叫。
P粉2383558602023-08-22 16:58:04
語法和瀏覽器支援。
querySelector
在你想要使用更複雜的選擇器時更有用。
例如,所有從屬於foo類別的元素的列表項目:.foo li
:
字元在選擇器中有特殊意義。你需要對它進行轉義。 (選擇器轉義字元在JS字串中也有特殊意義,所以你也需要轉義它)。
document.querySelector("#view\:_id1\:inputText1")