Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DOM进阶之querySelector和querySelectorAll #191

Open
FrankKai opened this issue Mar 21, 2020 · 0 comments
Open

DOM进阶之querySelector和querySelectorAll #191

FrankKai opened this issue Mar 21, 2020 · 0 comments
Labels

Comments

@FrankKai
Copy link
Owner

FrankKai commented Mar 21, 2020

之所以写这篇博文,是因为在写热力图的过程中,需要匹配一组class以foo-bar-xxx开头的元素,然后对为这组元素增加自定义事件监听器。
然而在匹配一组class以foo-bar-xxx开头的元素这一步我就卡住了,虽然知道有多种查询DOM节点的方法,但是并不清楚到底用哪一个,查找资料后通过 querySelectorAll和属性选择器匹配到了元素。但是对于这两个方法还是一知半解,所以开此issue性系统学习一下。

image

this.tableCells = document.querySelectorAll('td[class^="custom-alpha"]');

关于实际的应用,可以查阅这篇文章:如何为DOM创建自定义事件?

  • 使用选择器定位DOM元素
    • querySelector和querySelectorAll的区别
    • 选择器语法
    • 选择器有哪些?
  • querySelector()
    • 匹配到谁?
    • 子元素可以通过querySelector找到上级的元素吗?
    • Document.querySelector与Element.querySelector区别是什么?
  • querySelectorAll()
    • 可以选择伪元素吗?
    • 如何选中所有以某某前缀开头的元素?
    • NodeList是一个普通的数组吗?
    • 限制选择器作用域的:scope伪元素是什么?

使用选择器定位DOM元素

querySelector和querySelectorAll之父 NodeSelector interface
规范为Document,DocumentFragment或Element增加了2个新方法:

querySelector和querySelectorAll的区别

  • querySelector()
    返回节点子树第一个匹配到的Element节点。如果没有匹配的节点,返回null。

  • querySelectorAll()
    返回一个子树内包含所有匹配Element节点的NodeList。若没有匹配到,返回一个一个空的NodeList。

如果对Element和NodeList不理解的话,可以查看DOM进阶之Element和NodeList

需要特别注意一点:
document.querySelectorAll()得到的NodeList是static nodelist,意味着如果DOM发生变化,查询到的集合不会更新。而其他的DOM查询方法是可以的。因为它们查询到的是live nodelist。

选择器语法

选择器可以接收一个或多个用逗号分隔的选择器。

选择css class为warning或note的所有p元素:

const pTagAll = document.querySelectorAll("p.warning, p.note");

选择id为main,basic,exclamation中一个的元素:

const idTag = document.querySelector("#main, #basic, #exclamation");

选择器有哪些?

是所有css选择器。注意是css选择器。

image
https://developer.mozilla.org/en-US/docs/Learn/CSS/Building_blocks/Selectors

querySelector()

querySelector返回匹配器匹配到的第一个元素。

const element = baseElement.querySelector(selectors);
const element = document.querySelector(selectors);

匹配到谁?

匹配到baseElement的第一个后代元素。

const el = document.body.querySelector("style[type='text/css'], style:not([type])");
<div>
  <h5>Original content</h5>
  <p> inside paragraph<span>inside span</span>inside paragraph</p>
</div>
<div>
  <h5>Output</h5>
  <div id="output"></div>
</div>
const baseElement = document.querySelector("p");
document.getElementById("output").innerHTML = (baseElement.querySelector("div span").innerHTML);

子元素可以通过querySelector找到上级的元素吗?

亲测不可以。

因此可以将querySelector理解为从上往下找。若不需要指定特殊的baseElement,可以直接通过document查找。

Document.querySelector与Element.querySelector区别是什么?

Document继承自HTMLElement,而HTMLElement又继承自Element,所以本质上查询方法一样。
但是我们这里将根浏览器根节点当做Document,根节点的子节点当做Element,所以区别的话那就是查询范围不同,Document.querySelector作用域整个文档所有后代节点,而Element.querySelector作用域选中元素的后代节点。

<html>
    <body>
        <div>
            <p>Hello World.</p>
            <ul>
                 <li>foo</li>
                 <li>bar</li> 
                 <li>baz</li>
            </ul>
        </div>     
    </body>
</html>

Document.querySelector查询所有html,body等等全部子元素。
Element为div时,Element.querySelector查询p,ul,li等等子元素。

querySelectorAll()

querySelectorAll()通过选择器匹配元素的后代节点,返回一个static(not live)NodeList。

const element = baseElement.querySelectorAll(selectors);
const element = document.querySelectorAll(selectors);

#### 可以选择伪元素吗?
如果选择器包含伪元素,返回的是空。

#### 如何选中所有以某某前缀开头的元素?
通过属性选择器和querySelectorAll配合。
```html
<section class="box" id="sect1">
  <div class="funnel-chart-percent1">10.900%</div>
  <div class="funnel-chart-percent2">3700.00%</div>
  <div class="funnel-chart-percent3">0.00%</div>
</section>
const refs = document.querySelectorAll(`[data-name*="funnel-chart-percent"]`);

NodeList是一个普通的数组吗?

不是。
它没有slice,some,map等方法,但是可以通过for循环,forEach等多种方式遍历。可以查阅:DOM进阶之Element和NodeList

限制选择器作用域的:scope伪元素是什么?

<div class="outer">
  <div class="select">
    <div class="inner">
    </div>
  </div>
</div>

错误匹配出不属于自己的子类。

var select = document.querySelector('.select');
var inner = select.querySelectorAll('.outer .inner');
inner.length; // 1, not 0!

这是因为默认情况下,querySelectorAll() 只验证选择器中最后一个元素是不是在选择范围内。

如何解决这个问题呢?通过:scope去限定搜索的作用域,使得querySelectorAll仅仅匹配baseElement的后代节点。

var select = document.querySelector('.select');
var inner = select.querySelectorAll(':scope .outer .inner');
inner.length; // 0

参考资料:
https://developer.mozilla.org/en-US/docs/Web/API/Document_object_model/Locating_DOM_elements_using_selectors
https://developer.mozilla.org/en-US/docs/Web/API/Element/querySelector
https://developer.mozilla.org/en-US/docs/Web/API/Element/querySelectorAll
https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelector
https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelectorAll

@FrankKai FrankKai added the HTML label Mar 21, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant