四、搜索 DOM

4.1 搜索具有 id 的元素

document.getElementById或者只使用id

javascript
1document.getElementById('elem').style.background = 'red' // 通过getElementById搜索对应元素
2// elem 是对带有 id="elem" 的 DOM 元素的引用
3elem.style.background = 'red' // 也可以直接通过id访问
4// id="elem-content" 内有连字符,所以它不能成为一个变量
5// ...但是我们可以通过使用方括号 window['elem-content'] 来访问它

使用 id 方式直接访问 dom 是一种兼容性的支持,并不推荐在项目开发中使用。可以用于在元素来源非常明显且不会跟变量名重复的情况。(可用于写 demo)

如果有具有相同名称的变量,那么则以变量名为优先。

保持 id 的唯一性,全局不要有重复的 id,否则使用搜索 API 搜索某一个元素时,可能会随机返回另一个元素。

document.getElementById 只能被在 document 上调用,没有 elem.getElementById

4.2 querySelectorAll

querySelectorAll(css_selector)方法可以搜索跟 CSS 选择器相匹配的所有元素。

querySelector(css_selector)方法可以搜索跟 CSS 选择器相匹配的第一个元素,相当于 querySelectorAll(css_selector)[0]

html
1<ul>
2  <li>The</li>
3  <li>test</li>
4</ul>
5<ul>
6  <li>has</li>
7  <li>passed</li>
8</ul>
9<script>
10  let elements = document.querySelectorAll('ul > li:last-child')
11
12  for (let elem of elements) {
13    alert(elem.innerHTML) // "test", "passed"
14  }
15  let element = document.querySelector('ul > li:last-child')
16  alert(element.innerHTML) // "test"
17</script>

querySelector 方法可以供 elem 调用

html
1<div class="container">
2  <div>123</div>
3</div>
4
5<script>
6  let containerElem = document.querySelector('.container')
7  let div = containerElem.querySelector('div')
8  console.log(div.innerHTML) // 123
9</script>

4.3 getElementsBy*

旧的 API 中还有类似通过标签、类等查找节点的方法。querySelector 功能更强大,写起来更短,所以这些旧 API 通常在老代码中存在

  • elem.getElementsByTagName(tag) 查询标签名的集合

    html
    1<h1>This is a static template</h1>
    2<script>
    3  const elem = document.getElementsByTagName('h1')
    4  console.log(elem[0].innerText) // This is a static template
    5</script>
  • elem.getElementsByClassName(className) 返回具有给定 css 类的元素

    html
    1<h1 class="template">This is a static template</h1>
    2<script>
    3  const elem = document.getElementsByClassName('template')
    4  console.log(elem[0].innerText)
    5</script>
  • document.getElementsByName(name) 返回在文档范围内具有给定 name 特性的元素。(很少用)

    html
    1<form action="" name="form">
    2  <input type="text" />
    3</form>
    4<script>
    5  const elem = document.getElementsByName('form')
    6  console.log(elem[0].children)
    7</script>

注意点:

  • 不要忘记字母 s
  • 返回的是一个集合(伪数组)

4.4 实时的集合

所有的“getElementsBy*”返回的都是实时的集合。这样的集合始终反映的是文档的当前状态,并且在文档发生更改时会自动更新。

html
1<div>First div</div>
2
3<script>
4  let divByGetElements = document.getElementsByTagName('div')
5  let divBySelector = document.querySelectorAll('div')
6  console.log(divByGetElements.length) // 1
7  console.log(divBySelector.length) // 1
8</script>
9
10<div>Second div</div>
11
12<script>
13  console.log(divByGetElements.length) // 2
14  console.log(divBySelector.length) // 1
15</script>

上面的例子中,通过两种方式搜索出来的 div,在文档发生改变后,通过getElementsBy*获取的元素集合更新了,而通过querySelector获取的元素集合是静态的,不会实时更新。

4.5 matches

matches 可以检查elem是否和 css 选择器相匹配。它返回布尔值。

当我们遍历元素时,可以用这个 API 过滤我们需要的元素

javascript
1<a href="http://example.com/file.zip">...</a>
2<a href="http://ya.ru">...</a>
3
4<script>
5  // 不一定是 document.body.children,还可以是任何集合
6  for (let elem of document.body.children) {
7    if (elem.matches('a[href$="zip"]')) {
8      alert("The archive reference: " + elem.href );
9    }
10  }
11</script>

4.6 closest

elem.closest(css_selector)这个 API 可以返回最靠近的并且与 css 选择器相匹配的祖先。elem 自己也会被搜索。

换句话说,方法closest在元素中得到了提升,并检查每个父级和自己。如果与 css 选择器相匹配,则会返回对应的祖先元素(包括自己)

html
1<h1>这是外层元素</h1>
2<div>
3  <ul>
4    <li>li1</li>
5    <li>li2</li>
6    <li>li3</li>
7  </ul>
8</div>
9<script>
10  let elem = document.body.querySelector('li')
11  console.log(elem.closest('li').innerHTML) // li1
12  console.log(elem.closest('ul').tagName) // UL
13  console.log(elem.closest('div').tagName) // DIV
14  console.log(elem.closest('h1').tagName) // 找不到
15</script>

4.7 contains

elemA.contains(elemB)这个 API 可以用来检查元素 A 是否是另一个元素 B 的祖先(元素 B 是否在元素 A 内),它返回 boolean 值。

如果 elemA===elemB,那么会返回 true

html
1<h1>这是外层元素</h1>
2<div>
3  <ul>
4    <li>li1</li>
5    <li>li2</li>
6    <li>li3</li>
7  </ul>
8</div>
9<script>
10  let divElem = document.body.querySelector('div')
11  let h1Elem = document.body.querySelector('h1')
12  let ulElem = divElem.querySelector('ul')
13  let liElem = ulElem.querySelector('li')
14  console.log(divElem.contains(ulElem)) // true
15  console.log(divElem.contains(liElem)) // true
16  console.log(ulElem.contains(liElem)) // true
17  console.log(divElem.contains(h1Elem)) // false
18</script>

4.8 小结

在 DOM 中搜索节点,可以用以下方式:

方法名搜索方式能够给元素调用实时性
querySelectorCSS-selector✅❌
querySelectorAllCSS-selector✅❌
getElementByIdid❌❌
getElementsByTagNametag 或者 *✅✅
getElementsByClassNameclass✅✅
getElementsByNameName❌✅

最常用的是 querySelector 和 querySelectorAll

此外:

elem.matches(css_selector)这个 API 用于检查 elem 与 css 选择器是否匹配

elem.closest(css_selector)这个 API 用于检查 elem 与 css 选择器相匹配的祖先(包括自己)

elemA.contains(elemB)这个 API 用于检查子级与父级的关系 —— 如果 elemA 包含 elemB(或者相等),则返回 true