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结构树
看看"DOM结构树"上那些是认识的?
Document(只不过首字母是大写的)、Element(元素的意思)、Text(文本)、Comment(注释)、HTMLElement(Element加一个HTML,就叫html元素)
1、Doucment
从Document入手,首字母是大写的Document和首字母小写的document有什么联系呢?
控制台输入首字母小写document,输入回车document代表整个文档
控制台输入首字母大写的Document,回车返回一个函数
返回一个首字母大写的函数,什么函数需要首字母大写?只有构造函数需要首字母需要大写,构造函数是生成对象用的,
这个首字面大写的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方法定义在Document.prototype上,即Element节点上不能使用。
2. getElementsByName方法定义在HTMLDocument.prototype上,即非html中的document以外不能使用(xml document,Element)
3. getElementsByTagName方法定义在Document.prototype 和 Element.prototype上
4. HTMLDocument.prototype定义了一些常用的属性,body,head,分别指代HTML文档中的<body><head>标签。
5. Document.prototype 上定义了documentElement属性,指代文档的根元素,在HTML文档中,他总是指代<html>元素
6. getElementsByClassName、querySelectorAll、querySelector在Document,Element类中均有定义
1、getElementById
getElementById方法定义在首字母大写的Document.prototype上,说明无论HTML还是XML都能用,同时也说明Element不能用这个方法
2、getElementsByName
getElementsByName方法定义在HTMLDocument.prototype上,说明非HTML的XML不能用
Node - Document - |- HTMLDocument 可以用使用 getElementsByName
|- XMLDocument 不能使用 getElementsByName
3、getElementsByTagName
第三点挺有用的,getElementsByTagName方法是最常用的,它定义在Document.prototype和Element.prototype上
就是说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);
6、最后一条
getElementsByClassName、querySelectorAll、querySelector在Document和Element类中均有定义
div.getElementsByClassName(''); // 也就是说在div这样的元素下可以用getElementsByClassName方法