文件物件模型--DOM

BOM(Browser Object Model 浏览器物件模型)的重点在於浏览器的功能,完全由各家浏览器厂商自行开发。而DOM(Document Object Model 文件物件模型)则是W3C所制定的共同文件规范,提供跨浏览器且标准的文件处理介面。

DOM(Document Object Model 文件物件模型),是一个有阶层的树状结构,一个节点就是一个标签,根节点下有子节点,子节点下还有子节点,形成上下结构的关系,这样的树状结构,我们称之为「DOM Tree」。

《0陷阱!0误解!8天重新认识JavaScript》一书中有提到:

「DOM API定义了让JavaScript可以存取、改变HTML架构、样式和内容的方法,甚至对节点绑定的事件。」

当浏览器载入一个网页时,浏览器会分析这个网页的HTML,依照它的HTML结构建立一个DOM Tree。DOM的学习重点就在於掌握节点根结点之间的关系,学会如何控制DOM就可以控制网页,做出良好的互动体验。

如何透过DOM API取得节点:

//根据传入的id 名称,找到DOM里面相同id名称的节点。
document.getElementById('idName');

//根据传入的tag名称,回传所有符合条件的NodeList物件。
document.getEleMentsByTagName('tagName');

//根据传入的class名称,回传所有符合条件的NodeList物件。
document.getElementByClassName('className')

//根据所设定的selector条件(class或id都可以),回传第一个符合条件的节点。
document.querySelector('selector');

//根据所给定的selector条件,回传所有符合条件的 NodeList。
document.querySelectorAll;

假设网页上有一个h1的标签节点,里面没有任何内容:

<h1 id="hello"></h1>

我们利用document.getElementById('hello')来取得#hello节点,然後修改textContent属性:

document.getElementById('hello').textContent = '郭靖在华山论剑向大家说 Hello World!'

这就是取得节点,改变HTML内容的方法。

你有发现吗?不管是document.getElementById('idName') 或是document.querySelector('selector')都是由document开头。让我们来看看DOM Tree的图,可以发现document是整个DOM Tree的根结点,所以在存取DOM节点时,都要从document出发。

我们观察一下DOM Tree的图可以发现,节点之间有上下分层的关系,也有同一层节点间相邻的关系,所以节点与节点之间的关系可以区分为:

  • 父子关系:document在最上层,其他的节点若有上层的节点,上层的节点称为「父节点」(Parent Node),下层的节点称为「子节点」(Child Node)。就像王阳明的徒弟是「全真七子」,而全真七子之一的丘处机,他的徒弟是尹志平等人。
  • 兄弟关系:同一层的节点如果它们有同一个「父节点」,那它们之间就是「兄弟关系」,就像王阳明的徒弟「全真七子」,他们之间是师兄弟关系。

Node.childNodes

「所有的DOM节点物件都有childNodes属性,且这种属性无法修改」,那我们要如何知道一个节点是否有子节点? 这时候可以利用Node.hasChildNodes()来检查:

<div id="sword">
  <ul>
    <li>1 东邪</li>
    <li>2 西毒</li>
    <li>3 南帝</li>
    <li>4 北丐</li>
    <li>5 中神通</li>
  </ul>
</div>
var node = document.getElementById('sword');

if(node.hasChildNodes()){
  for(var i=0; i <node.childNodes.length; i++)
    console.log(i + node.childNodes[i].nodeName);
}

来看一下console出来的结果:

cosole视窗中列出了查询的结果,我为查询的节点加上了编号,除了"LI"之外,还出现了"0#text"之类的字串,这是因为换行符号的空白节点也被查询了出来。如果不换行的话,"0#text"就不会出现。

Node.firstChild

Node.firstChild用来取得Node节点的第一个子节点,如果没有子节点的话,则回传null。而子节点包括空白节点,例如HTML Tag之间的换行符号。

<div id="sword">
  <ul id="fiveHero"><li class="firstHero">1 东邪</li><li>2 西毒</li><li>3 南帝</li><li>4 北丐</li><li>5 中神通</li>
  </ul>
</div>
var node = document.getElementById('fiveHero');
console.log(node.firstChild.className);   //firstHero

Node.lastChild

Node.lastChild可以取得Node节点的最後一个子节点,如果没有子节点的话,则一样是传回null。而子节点包括空白节点,例如HTML Tag之间的换行符号。

<div id="sword">
  <ul id="fiveHero"><li class="firstHero">1 东邪</li><li>2 西毒</li><li>3 南帝</li><li>4 北丐</li><li class="lastHero">5 中神通</li></ul>
</div>
var node = document.getElementById('fiveHero');
console.log(node.lastChild.className);         //"lastHero"

Node.parentNode

Node.parentNode可以取得Node节点的父节点。

<div id="sword">
  <ul id="fiveHero"><li class="firstHero">1 东邪</li><li>2 西毒</li><li>3 南帝</li><li>4 北丐</li><li class="lastHero">5 中神通</li></ul>
</div>
var node = document.getElementById('fiveHero');
console.log(node.parentNode.tagName);          //"DIV"

Node.previousSibling

有同一个父元素,位於同一层的节点称为「兄弟节点」,而Node.previousSibling可以取得Node节点的前一个兄弟节点。

<div id="sword">
  <ul id="fiveHero">
    <li class="firstHero">1 东邪</li><li class="secondHero">2 西毒</li><li class="thirdHero">3 南帝</li><li class="fifthHero">4 北丐</li><li class="lastHero">5 中神通</li>
  </ul>
</div>
var node = document.querySelector('.secondHero');
console.log(node.previousSibling.className);     //"firstHero"

Node.nextSibling

Node.nextSibling可以取得Node节点的下一个兄弟节点。

<div id="sword">
  <ul id="fiveHero">
    <li class="firstHero">1 东邪</li><li class="secondHero">2 西毒</li><li class="thirdHero">3 南帝</li><li class="fifthHero">4 北丐</li><li class="lastHero">5 中神通</li>
  </ul>
</div>
var node = document.querySelector('.secondHero');
console.log(node.nextSibling.className);       //"thirdHero"

由上面几个操作,可以知道透过节点的抓取,我们可以取得节点的资讯,进而改变网页的结构、内容以及样式,懂得控制节点,就可以控制网页的呈现与使用者互动。


<<:  Day06 - 监控 Sidekiq 有无正常运作(或执行超过多久)

>>:  【Day4】重要底层系统篇-Base

[第十三只羊] 迷雾森林舞会VI devise登入

天亮了 昨晚是平安夜 关於迷雾森林故事 焦虑抑制剂 10号:哈罗大家好,我是海马诚实小君,其实原本一...

Trouble with Distributed Systems (1)

从 2020 Day 21 - Replication 开始到现在,我们大多都是在谈系统出错了怎麽办...

Day 01:前言,这批很纯,快进来吧!

这三小系列 本来我报名了软件开发组,但是我某天忘记发文了~ 所以再开了新系列拿个参加奖 Who Am...

14【推坑】考 APCS 升大学大有优势

提完了那麽多有关 APCS 的事,这次想要分析考 APCS 能够有怎样的好处。 权威性: APCS ...

[D24] 物件侦测(5)

前一篇物件侦测(4)停在 YOLOv1 的缺点上,现在就要来说 YOLOv2了! YOLOv2 YO...