Go to comments

JavaScript DOM继承树

复习DOM

DOM是一套编程接口,是让JavaScript能操作HTML和XML的一系列接口,当然可以间接的操作CSS。DOM操作提供了一系列方法的集合,这一系列方法的集合我们叫做接口,这些方法集合有对HTML元素的增、删、改、查


之前是查找元素的方法,查找元素的方法大致分两类,一类是document.getElement...、一类是querySelect...

查找的方法还有一些,基于关系的查找方法,第一类"遍历节点树"不管是什么类型的节点都能遍历出来,比如跟这个元素相邻的,还是这个元素的子元素、父元素,都能基于一个树型结构的关系查找出来。还有"遍历元素节点树"是基于元素节点的节点树来查找元素的。


比如div下面有几个节点?

<div>
	<p></p>
	<span></span>
	<!-- this is conmment -->
</div>


<script>

    var oDiv = document.getElementsByTagName('div')[0];
    
    console.log(oDiv.childNodes); // NodeList(7) [text, p, text, span, text, comment, text]
    
</script>

有7个子节点,但凡页面里能展示出来的,包括展示不出来的,比如注释都算节点,节点有节点类型nodeType


节点类型nodeType:

1 - 是元素节点

2 - 是属性节点(属性节点,不用太记,没什么用)

3 - 是文本节点

8 - 是注释节点

9 - 文档节点document(document自己是一个节点,叫document节点)


这几个记住1、3就可以,8和9不是那么常用,2基本上就不用,11以后在说,

div下面有7个节点,那div下有几个元素节点?只有两个元素节点一个是p、一个是span

节点树

遍历节点树遍历元素节点树的使用上都是一样的,但是它们的兼容性不同,

遍历元素节点树虽然是方便了一些,但是它的兼容性不好,除了chilren以外基本上所有的方法IE都用不了。


PS : 

所说的IE不兼容是指IE9及IE9以下,因为IE9以上以及现在新的IE用的内核不是原来的trident内核了,IE9以上的浏览器和原来的老IE浏览器划分开来了,新版的IE浏览器IE10、IE11、IEedge和chome没什么太大区别,我们说的IE不支持指的是IE9以及IE9以下。


节点的四个属性nodeName、nodeValue(只有文本节点、注释节点可用读写)、nodeType、attributes,

这四个属性还有一个Node.hasChildNodes()方法里面,nodeType属性是最重要的,nodeType作为以后判断元素是什么类型的关键属性的存在,任何一个元素都有nodeType属性,它能显示这个元素是什么类型的。

一、DOM结构树

原型还记得吗?简单说一下什么叫原型,

每一个构造函数都可以构造出对象,构造函数上面会有一个属性或者说函数上面都会有一个属性叫prototype(这东西是天生的)


prototype作为这个构造函数的原型有什么用呢?

所有构造函数产生的对象都会继承自这个原型上的方法、属性,这个构造函数构造出的对象都能使用,


prototype作为一个原型作为一个祖先的存在

// Person.prototype

function Person(){

}


接下来看DOM结构树

image.png

看看"DOM结构树"上那些是认识的?

Document(只不过首字母是大写的)、Element(元素的意思)、Text(文本)、Comment(注释)、HTMLElement(Element加一个HTML,就叫html元素)

1、Doucment

从Document入手,首字母是大写的Document和首字母小写的document有什么联系呢?


控制台输入首字母小写document,输入回车document代表整个文档


控制台输入首字母大写的Document,回车返回一个函数

image.png

返回一个首字母大写的函数,什么函数需要首字母大写?只有构造函数需要首字母需要大写,构造函数是生成对象用的,

这个首字面大写的Document我们可以把它理解成构造函数,只不过这个构造函数有点特殊,特殊在我们不能new操作它,这是系统留给自己new的。


这个构造函数对我们有什么帮助呢?

有帮助,构造函数上有一个"原型",能给构造函数生产出来的对象使用,

Doucment如果作为首字母小写document原型的话,说明在Document.prototype加上属性abc,首字母小写的document上就能访问到abc

Document.prototype.abc = '来这个世界';

console.log(document.abc); // 来这个世界


这个DOM结构树代表的就是一系列的继承关系,这个继承关系我们慢慢缕一缕


首字母大写的Document原型上写的东西,首字母小写的document能使用,其实还不然,

Document不是document直接的构造函数跟它没关系,document的构造函数是HTMLDocument(document --> THMLDocument)。


那Document跟HTMLDocument有什么联系呢?

HTMLDocument.prototype就是document的原型

// 原型是一个对象,这对象上的属性和方法,首字母小写document受益了,然后还有一个属性__proto__指向的原型是Document.prototype

HTMLDocument.prototype = {
	__proto__ : Document.prototype
}

function HTMLDocument(){

}

var document = new HTMLDocument();


Document.prototype是HTMLDocument.prototype的原型,它们之间是逐步继承的关系,这是一个原型链

document --继承自--> HTMLDocument.prototype --继承自--> Document.prototype

所以上面在Document.prototype上写的'来这个世界',直接也能受益到document上,因为是原型链继承过去的,


在HTMLDocument.prototype写一个属性bcd,document上也能访问这个属性

HTMLDocument.prototype.bcd = "123";

console.log(document.bcd); // 123


做一个小实验,

Document.prototype.abc=1,然后HTMLDocument.prototype.abc=2,访问document.abc是1还是2 ?

Document.prototype.abc = 1;

HTMLDocument.prototype.abc = 2;

console.log(document.abc); // 2

document.abc必须2,就近继承符合一个继承关系


整个的这个"DOM结构树"它表示的就是一种继承关系,这继承关系干什么用?

首字母大写的Document下面应该有两个分支,一个分支是HTMLDocument,另一个分支是XMLDocument(xml现在不怎么用图上就没写)

Node - Document - |- HTMLDocument

                                 |-  XMLDocument

也就是说HTML文档的document方法直接继承自HTMLDocument,XML文档的doucment的方法直接继承自XMLDocument,

然后这个首字母大写的Document上的一些方法应该提供的是HTML能用,XML也能用的一些方法。

Document上还有一根线连在Node上了

console.log(Node); // ƒ Node() { [native code] }

这个Node也是一个构造函数,但是Node是这一系列所有东西最顶头的那个了

2、CharacterData

CharacterData下面有两个分支,一个是Text一个是Comment

Node - CharacterData - |- Text

                                       |- Comment

Text说明文本节点的方法直接继承自Text.prototype,注释节点的方法直接继承自Comment.prototype,然后在一层一层在向上继承形成一个原型链

3、Element

Node下面有个Element,然后Element下面有HTMLElement(肯定还有一个XMLElement)


THMLElement下面有HTMLHeadElement、HTMLBodyElement、HTMLTitElement…这些是什么意思?

HTMLHeadElement           是head标签

HTMLBodyElement           是body标签

HTMLTitleElement             是title标签

HTMLParagraphElement   是p标签

……


这些标签(head、body、title、p…)所独有的方法先继承自这些HTMLHeadElement、HTMLBodyElement、HTMLTitleElement、HTMLParagraphElement…

比如给HTMLHearElement上加了一个方法,把这个head标签选中后,head标签就能使用这个方法


试一下,就用body标签

HTMLBodyElement.prototype.abc = "demo";

var body = document.getElementsByTagName('body')[0]; // 选择body标签

console.log(body.abc); // demo


给HTMLBodyElement上加abc属性,除了body上有,换一个看看head有没有?

HTMLBodyElement.prototype.abc = "demo";
var body = document.getElementsByTagName('body')[0];
console.log(body.abc); // abc


var head = document.getElementsByTagName('head')[0]; // 选head标签

console.log(head.abc); // undefined

head上没有返回undefined,因为abc属性就不属于它


如果在HTMLElement.prototype上写一个东西,body、head两个就都可以使用了

HTMLElement.prototype.LiLi = 'Glee';


var body = document.getElementsByTagName('body')[0];
console.log(body.LiLi); // Glee

var head = document.getElementsByTagName('head')[0];
console.log(head.LiLi); // Glee

4、DOM结构树继承关系

这是一系列继承关系,这个"DOM结构树"代表的就是这一系列继承关系,这些继承关系在下一篇学习中就可以带来很多帮助


继续研究"DOM结构树"到底一层一层往上返,到底能返出什么东西


document.__proto__  document的__proto__指代的是它的原型

console.log(document.__proto__); // HTMLDocument {Symbol(Symbol.toStringTag): "HTMLDocument", constructor: ƒ}


document.__proto__.__proto__  document原型的原型是Document{}

console.log(document.__proto__.__proto__); // Document {…}


document.__proto__.__proto__.__proto__  然后再打印原型是 Node

console.log(document.__proto__.__proto__.__proto__); // Node


document.__proto__.__proto__.__proto__.__proto__  然后再来看看Node上有没有原型,返回EventTarget(EventTarget是一个事件)

console.log(document.__proto__.__proto__.__proto__.__proto__); // EventTarget


然后再往上看看有没有原型,看看它最终他继承自谁,最终也是继承在Object.prototype

console.log(document.__proto__.__proto__.__proto__.__proto__.__proto__); // Object.prototype

Object.prototype依然是DOM元素原型的一个终端,DOM也能使用正常对象祖先的东西


比如document.body指代的就是body不用特别选,系统已经定义好了,document.body.toString()能用toString这个方法吗?

console.log(document.body.toString()); // [object HTMLBodyElement]

返回[object HTMLBodyElement],object告诉我们是个对象,什么对象呢?HTMLBodyElement对象,把对象的信息给我们展示出来


这是一系列"DOM结构树",我们了解一下继承关系就可以了,接下来看下篇

二、DOM基本操作

1、getElementById

getElementById方法定义在首字母大写的Document.prototype上,说明无论HTML还是XML都能用,同时也说明Element不能用这个方法

01.png

2、getElementsByName

getElementsByName方法定义在HTMLDocument.prototype上,说明非HTML的XML不能用

Node - Document - |- HTMLDocument  可以用使用 getElementsByName

                                 |-  XMLDocument   不能使用 getElementsByName

3、getElementsByTagName

第三点挺有用的,getElementsByTagName方法是最常用的,它定义在Document.prototype和Element.prototype上

02.png

就是说getElementsByTagName方法在Document定义了、Element也定义了,那都能用


什么叫那都能用?

比如现在就要选div里面那个span,有什么好的方法

<div>
	<span>1</span>
</div>
<span>2</span>


<script>

    // 先选div,这个方法这样用没问题,因为在Document上定义了,首写字母小写的document上就可以与用
    var oDiv = document.getElementsByTagName('div')[0]; 

    // 然后选span,getElementsByTagName定义在"Element.prototype",div元素算Element上的可以用这个方法,语法上没问题
    var oSpan = oDiv.getElementsByTagName('span')[0];

    console.log(oSpan); // <span>1</span>

</script>

document.getElementsByTagName 的意思是在整个文档下去找,oDiv.getElementsByTagName 的意思是div调用就是在div的区域里面去找,把区域锁定了,这样也可以选出span,

以后这种方法很常见,到正常开发的时候经常会利用先选择父级,然后在它父级里在一次选择一个元素来定位一个元素,这么选方便。


这个getElementsByTagName方法里面可以写*

*官方叫通配符选择器,通配符选择器也是一种标签选择器,它选的是所有标签

<div>
	<span>1</span>
</div>
<span>2</span>


<script>

    var All = document.getElementsByTagName('*');

    console.log(All); // HTMLCollection(9) [html, head, meta, title, body, div, span, span, script]

</script>

选所有标签的方法 document.getElementsByTagName('*')里面写*

4、HTMLDocument.prototype定义了一些常用的属性,body,head,分别指代HTML文档中的<body><head>标签

HTMLDocument.prototype定义了一些常用的属性(也就是说只有HTMLDocument上可以用),这些常用属性有body、head分别指代HTML文档中的<body>标签、<head>标签,

意思是document上有一个直接的属性document.body,还有一个直接的属性document.head


它俩解决的问题是

document.body  存的就是body标签

document.head  存的就是head标签

也就是说用body和用head的时候不用重新选了,系统已经选好了。


以后用body的时候document.body就是body标签,document.head就是head标签

console.log(document.body); // <body>…</body>

console.log(document.head); // <head>…</head>

5、第五条也是一个预定义的问题

在首字母大写的Document.prototype上定义了documentElement属性,指代文档的根元素,在HTML文档中,它总是指代<html>元素。


有body、有header,有没有预定义的html呢?

document.docuemntElement 指代的就是HTML,这个要特殊记了它没有那么形象

console.log(document.documentElement);

image.png

6、最后一条

getElementsByClassName、querySelectorAll、querySelector在Document和Element类中均有定义

div.getElementsByClassName(''); // 也就是说在div这样的元素下可以用getElementsByClassName方法



Leave a comment 0 Comments.

Leave a Reply

换一张