资讯专栏INFORMATION COLUMN

通过DOM API 查找节点

shengguo / 2092人阅读

摘要:我们可以通过来检查某个节点是否有子节点。通过可以用来取得父元素,返回值可能会是一个元素节点根节点或节点。与类似,通过可以取得同层之间的下一个节点,如果已经是最后一个节点,则返回。

在上一篇的分享当中,我们简单介绍了BOM 与DOM,也了解到JavaScript 是怎么通过它们提供的方法来与浏览器进行沟通。

当一个网页被载入到浏览器时,浏览器会首先分析这个HTML 文档,然后会依照这份HTML 的内容解析成DOM (Document Object Model,即文件对象模型)。

而DOM 是W3C 制定的一个规范,它是独立于平台与语言的标准。换言之,只要遵守这样的规范,不管是什么平台或者是什么语言开发,都可以通过DOM 提供的API 来操作DOM 的内容、结构与样式。

所以说,DOM 是网页的根本,懂得控制DOM就可以控制整个网页,做出良好的互动体验

那么在今天的分享中,我们就继续来介绍DOM API 查找节点的方法吧。

前言:script标签放哪里有区别吗?

针对

接着,我们试着把

咦?怎么什么都没有呢?而且也没有错误信息,JavaScript真的如大家说的一样,很垃圾吗?

冷静一下,容我解释一下。

前面说过,当一个网页被载入到浏览器时,浏览器会先分析这个HTML 文档,由上而下依序来读取解析:

所以上面jsbin例子中,当浏览器在 ... 之间遇到

上一篇文章说过,document对象是DOM tree的根节点,所以当我们要存取HTML时,都从document对象开始。而DOM的节点类型除了HTML元素节点(element nodes)外,还有文字节点(text nodes)、注释节点(comment nodes)等。

而常见的DOM 选取方法有下列这些:

// 根据传入的值,找到 DOM 中 id 为 "xxx" 的元素。
document.getElementById("xxx");

// 针对给定的 tag 名称,返回所有符合条件的 NodeList 对象(节点的集合)
document.getElementsByTagName("xxx");

// 针对给定的 class 名称,返回所有符合条件的节点集合
document.getElementsByClassName("xxx");

// 针对给定的 Selector 条件,返回第一个 或 所有符合条件的节点集合
document.querySelector("xxx"); 
document.querySelectorAll("xxx");
DOM 节点的类型

DOM 常用的节点类型有下面几种:

可以通过节点类型常数或是对应数值来判断:

document.nodeType === Node.DOCUMENT_NODE;   //true
document.nodeType === 9;   //true

其他不常用或是已经废弃的部分可以参考:MDN Node.nodeType一节。

DOM 节点间的查找遍历(Traversing)

由于DOM 节点有分层的概念,于是节点与节点之间的关系,我们大致上可以分成以下两种:

父子关系:除了document之外,每一个节点都会有个上层的节点,我们通常称之为「父节点」 (Parent node),而相对地,从属于自己下层的节点,就会称为「子节点」 (Child node)。

兄弟关系:有同一个「父节点」的节点,那么他们彼此之间就是「兄弟节点」(Siblings node)。

而隔层的节点基本上没有直接关系。

上图中水平方向的邻层节点为父子关系,垂直方向的同层节点为兄弟关系。

Node.childNodes

所有的DOM节点对象都有childNodes属性,且此种属性无法修改。

我们可以通过Node.hasChildNodes()来检查某个DOM节点是否有子节点。

var node = document.querySelector("#hello");

// 如果 node 內有子元素
if( node.hasChildNodes() ) {
    
    // 可以通过 node.childNodes[n] (n 为数字索引) 取得对应的节点
    // 注意,NodeList 对象內容为即时更新的集合
    for (var i = 0; i < node.childNodes[i].length; i++) {
       // ...     
    }; 
}

Node.childNodes返回的可能会有这几种:

HTML 元素节点(element nodes)

文字节点(text nodes),包含空格

注释节点(comment nodes)

Node.firstChild

Node.firstChild可以取得Node节点的第一个子节点,如果没有子节点则返回null

要注意的是,子节点包括空白节点,如下面例子:

<p>
  <span>span 1span>
  <span>span 2span>
  <span>span 3span>
p>

<script>
  var p = document.querySelector("p");    
  
  // tagName 属性可以取得 node 的标签名称
  console.log(p.firstChild.tagName);      // undefined
script>

因为取得的是

与第一个中间的换行字元,所以p.firstChild.tagName会得到undefined。所以改成这样:

<p><span>span 1span><span>span 2span><span>span 3span>p>

<script>
  var p = document.querySelector("p");    

  // tagName 属性可以取得 node 的标签名称
  console.log(p.firstChild.tagName);      // "SPAN"
script>

把中间的换行与空白移除,就会得到预期中的"SPAN"了。

Node.lastChild

Node.lastChild可以取得Node节点的最后一个子节点,如果没有子节点则返回null

Node.firstChild一样的是,子节点也包括空白节点,所以像这样:

<p>
  <span>span 1span>
  <span>span 2span>
  <span>span 3span>
p>

<script>
  var p = document.querySelector("p");    
  
  // textContent 属性可以取得节点内的文字内容
  console.log(p.lastChild.textContent);      // "" (换行字元)
script>

得到的会是一个换行字元的空字符串。

移除节点之间多余的空白后:

<p><span>span 1span><span>span 2span><span>span 3span>p>

<script>
  var p = document.querySelector("p");    
  // textContent 属性可以取得节点内的文字内容
  console.log(p.lastChild.textContent);      // "span 3"
script>

输出的就会是正确的"span 3" 啦。

Node.parentNode

那么相较于Child系列,parentNode就单纯一些。

通过Node.parentNode可以用来取得父元素,返回值可能会是一个元素节点(Element node)、根节点(Document node)或DocumentFragment节点。

<p><span>span 1span><span>span 2span><span>span 3span>p>

<script>
  var el = document.querySelector("span");   
  console.log( el.parentNode.nodeName );    // "P"
script>

Node.previousSibling

看完了DOM父与子之后,接着来看看兄弟节点。

通过Node.previousSibling可以取得同层之间的前一个节点,如果node已经是第一个节点且前面无节点,则返回null

<p><span>span 1span><span>span 2span><span>span 3span>p>

<script>
  var el = document.querySelector("span");   
  console.log( el.previousSibling );    // null

  // document.querySelectorAll 会取得所有符合条件的集合,
  // 而 document.querySelectorAll("span")[2] 指的是「第三个」符合条件的元素。
  var el2 = document.querySelectorAll("span")[2];   
  console.log( el2.previousSibling.textContent );    // "span 2"
script>

Node.nextSibling

Node.previousSibling类似,通过Node.nextSibling可以取得同层之间的下一个节点,如果node已经是最后一个节点,则返回null

<p><span>span 1span><span>span 2span><span>span 3span>p>

<script>

  // document.querySelector 会取得第一个符合条件的元素
  var el = document.querySelector("span");

  console.log( el.nextSibling.textContent );    // "span 2"
script>

document.getElementsBy*与document.querySelector/ document.querySelectorAll的差异

今天分享了很多关于DOM的选取以及查找遍历的方式,其中,像是document.getElementById以及document.querySelector因为取得的一定只会有一个元素/节点,所以不会有indexlength属性。

document.getElementsBy**(注意,这里有个s)以及document.querySelectorAll则分别返回HTMLCollection与NodeList。

这两者其实是有点差别的,HTMLCollection只收集HTML element 节点,而NodeList除了HTML element 节点,也包含文字节点、属性节点等。当然两者也有类似的地方,虽然不能使用数组的method,但这两种都可以用数组索引的方式来存取内容,也就是伪数组。

另一个需要注意的地方是,HTMLCollection/NodeList在大部分情况下是即时更新的,但通过document.querySelector/document.querySelectorAll取得的NodeList是静态的。

啥意思呢?举个例子:

<div id="outer">
  <div id="inner">innerdiv>
div>

<script>

  // 
var outerDiv = document.getElementById("outer"); // 所有的
标签 var allDivs = document.getElementsByTagName("div"); console.log(allDivs.length); // 2 // 清空
下的节点 outerDiv.innerHTML = ""; // 因为清空了
下的节点,所以只剩下 outer console.log(allDivs.length); // 1 script>

如果改成document.querySelector的写法:

<div id="outer">
  <div id="inner">innerdiv>
div>

<script>

  // 
var outerDiv = document.getElementById("outer"); // 所有的
标签 var allDivs = document.querySelectorAll("div"); console.log(allDivs.length); // 2 // 清空
下的节点 outerDiv.innerHTML = ""; // document.querySelector 返回的是静态的 NodeList,不受 outerDiv 更新影响 console.log(allDivs.length); // 2 script>

那么以上就是今天所要介绍的内容啦。

在后续的文章会再继续说明DOM API新增/删除/修改节点的部分,欢迎持续关注。

如果觉得文章对你有些许帮助,欢迎在我的GitHub博客点赞和关注,感激不尽!

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/7268.html

相关文章

  • DOM 小总结

    摘要:在浏览器中,对象是继承自类型的一个实例,表示整个页面。它这种情况称为文档碎片,还无法显示在浏览器的画面中。创建一个文本节点并添加到新元素中的代码如下总结文档对象模型,是针对和文档的一个应用程序编程接口,描绘了一个层次化的节点树。 DOM 是什么 文档对象模型,是针对 HTML 和 XML 文档的一个 API (应用程序编程接口), 描绘了一个层次化的节点树。 D: document 当...

    hyuan 评论0 收藏0
  • DOM 小总结

    摘要:在浏览器中,对象是继承自类型的一个实例,表示整个页面。它这种情况称为文档碎片,还无法显示在浏览器的画面中。创建一个文本节点并添加到新元素中的代码如下总结文档对象模型,是针对和文档的一个应用程序编程接口,描绘了一个层次化的节点树。 DOM 是什么 文档对象模型,是针对 HTML 和 XML 文档的一个 API (应用程序编程接口), 描绘了一个层次化的节点树。 D: document 当...

    yzd 评论0 收藏0
  • 重学前端学习笔记(二十三)--狭义的文档对象DOM

    摘要:事件触发和监听事件相关。文档是一个由标签嵌套而成的树形结构,因此,也是使用树形的对象模型来描述一个文档。节点的写法三是树继承关系的根节点。七表示一个上的范围,这个范围是以文字为最小单位的。 笔记说明 重学前端是程劭非(winter)【前手机淘宝前端负责人】在极客时间开的一个专栏,每天10分钟,重构你的前端知识体系,笔者主要整理学习过程的一些要点笔记以及感悟,完整的可以加入winter的...

    Guakin_Huang 评论0 收藏0
  • 重学前端学习笔记(二十三)--狭义的文档对象DOM

    摘要:事件触发和监听事件相关。文档是一个由标签嵌套而成的树形结构,因此,也是使用树形的对象模型来描述一个文档。节点的写法三是树继承关系的根节点。七表示一个上的范围,这个范围是以文字为最小单位的。 笔记说明 重学前端是程劭非(winter)【前手机淘宝前端负责人】在极客时间开的一个专栏,每天10分钟,重构你的前端知识体系,笔者主要整理学习过程的一些要点笔记以及感悟,完整的可以加入winter的...

    wuaiqiu 评论0 收藏0

发表评论

0条评论

shengguo

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<