在JavaScript中,querySelector和querySelectorAll與getElementsByClassName和getElementById的區別
P粉442576165
2023-08-21 21:45:39
<p>我想知道<code>querySelector</code>和<code>querySelectorAll</code>與<code>getElementsByClassName</code>和<什麼區別? </p>
<p>從這個連結中,我了解到使用<code>querySelector</code>,我可以寫<code>document.querySelector(".myclass")</code>來取得具有類別名稱< ;code>myclass</code>的元素,以及<code>document.querySelector("#myid")</code>來取得具有ID<code>myid</code>的元素。但是我已經可以使用<code>getElementsByClassName</code>和<code>getElementById</code>來實現這個功能。哪個應該優先選擇? </p>
<p>另外,我在XPages工作,ID是動態產生的,包含冒號,看起來像這樣<code>view:_id1:inputText1</code>。所以當我寫<code>document.querySelector("#view:_id1:inputText1")</code>時,它不起作用。但是當我寫<code>document.getElementById("view:_id1:inputText1")</code>時,它起作用。有任何想法為什麼會這樣? </p>
對於這個答案,我將
querySelector
和querySelectorAll
稱為querySelector*,將getElementById
、getElementsByClassName
、getElementsByTagName
和getElementsByName
稱為getElement*。這些資訊的許多資訊可以在規範中進行驗證,很多是我在寫時執行的各種基準測試得出的。規格:https://dom.spec.whatwg.org/
#主要區別
querySelector
和getElementById
都傳回單一元素。querySelectorAll
和getElementsByName
都回傳NodeList。getElementsByClassName
和getElementsByTagName
都回傳HTMLCollection。 NodeList和HTMLCollection都被稱為元素的集合。這些概念在下表中總結。
詳細資訊、提示和範例
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*呼叫。
語法和瀏覽器支援。
querySelector
在你想要使用更複雜的選擇器時更有用。例如,所有從屬於foo類別的元素的列表項目:
#.foo li
:
字元在選擇器中有特殊意義。你需要對它進行轉義。 (選擇器轉義字元在JS字串中也有特殊意義,所以你也需要轉義它)。