DOM概念
什么是DOM: Document Object Model,是W3C规定的专门操作网页内容的统一的API标准,用DOM操作网页内容,几乎兼容所有浏览器。
简述HTML DHTML XHTML XML的区别
HTML:专门编写网页内容的语言,标签名固定
XHTML:更严格的XHTML标准
DHTML:一切可以实现网页动态效果的技术的统称,包含:HTML+CSS+JS
XML:可扩展的标记语言,专门存储和传输格式化数据的结构化文档结构,标 签名自定义
JSON:用js对象的语法描述数据,用于互联网中的数据传输
DOM树
网页的所有内容,在内存中其实是以树形结构存储的,树型结构最适合保存上下级关系,且可无限向下延伸。
一. 如何创建
当浏览器读取到HTML内容时,会自动创建DOM树。
1.读到HTML文档时,先创建根节点:document,document对象是整棵DOM树的树根,所有网页内容,都是document节点的后代节点。
2.开始顺序读取HTML文档的内容,创建子节点,网页中一切内容都是DOM树上的节点对象。
二. 节点对象Node
三大属性
1.node.nodeType
:表示节点的类型,值为数字(nodeType无法细致的区分每种元素的名称
document:9
元素节点:1
属性节点:2
文本节点:3
DOCTYPE:10
2.node.nodeName
:节点的名称
document:#document
元素节点:标签名(全大写)
属性节点:属性名
文本节点:#text
DOCTYPE:html
3.node.nodeValue
:节点的值,只用于获得属性的值和文本的内容
document:null
元素节点:null
属性节点:属性值
文本节点:文本内容
DOCTYPE:null
节点关系
1.节点树
包含所有节点的树结构,一切文本都是节点对象,包括看不见的空字符,也是节点对象(tab,空格,换行)。
elem.parentNode
=> 获得elem的父节点,返回值: 唯一的一个父节点对象
elem.childNodes
=> 获得elem的所有直接子节点,返回值: 所有直接子节点组成的类数组对象(不支持数组api)
elem.firstChild
=> 获得elem的第一个子节点
elem.lastChild
=> 获得elem的最后一个子节点
elem.previousSibling
=> 获得elem的前一个兄弟节点
elem.nextSibling
=> 获得elem的后一个兄弟节点
2.元素树
仅包含元素节点的树结构,优点是仅包含元素节点,不受空文本的干扰;缺点是无法访问文本节点,解决方法
elem.innerHTML
—取元素节点中的文本内容(字符串)
elem.parentElement
=> 获得elem的父元素
elem.children
=> 获得elem的所有直接子元素,返回值: 所有直接子元素组成的类数组对象
elem.firstElementChild
=> 获得elem下的第一个子元素
elem.lastElementChild
=> 获得elem下的最后一个子元素
elem.previousElementSibling
=> 获得elem的前一个兄弟元素
elem.nextElementSibling
=> 获得elem的后一个兄弟元素
节点遍历
1.递归遍历(循环效率低)
由于children和childNodes都只能查找直接子节点,无法查找更深层次,如需遍历指定父节点下的所有子节点时,我们需要采用递归遍历,先定义函数,仅遍历直接子节点,再对每个直接子节点,再次调用当前遍历函数本身。
另一个问题是children和childNodes返回的所有直接子节点对象,保存在一个类数组对象中,是一个动态集合,动态集合的缺点是不实际存储对象的完整属性,每次访问动态集合时,都会反复去DOM树查找。解决方法是遍历时,首先将length属性的值保存在变量中,用变量作为循环条件。
for(var i = 0, len = children.length; i < len; i ++){}
遍历时采取深度优先遍历,即每次同时碰到子元素和兄弟元素时,总是优先遍历子元素。所有子元素遍历完,才返回遍历兄弟元素。
2.节点迭代器: NodeIterator
NodeIterator按照深度优先的原则,依次读取指定父节点下的每个节点。
首先创建NodeIterator对象:
// 所有节点
var iterator = document.createNodeIterator(parent, NodeFilter.SHOW_ALL,null, false);
//所有元素节点
var iterator = document.createNodeIterator(parent, NodeFilter.SHOW_ELEMENT,null, false);
反复调用迭代器的nextNode()方法获取下一个节点对象
// 让iterator跳到下一个节点。到头返回null
var currNode=iterator.nextNode();
iterator.previousNode();//退一个节点
nextNode方法返回的是当前节点,调用一次nextNode,只向前跳一个节点,如果没有后续节点,返回null。
do{
var node = iterator.nextNode();
if (node != null) {
console.log(node.nodeName);
} else break;
} while (true)
3.TreeWalker(基本用法和NodeIterator完全一样)
// 提供了向四周跳转的方法
var walker=document.creatTreeWalker(parent,NodeFilter.SHOW_ALL,null,false);
walker.parentNode();
walker.firstChild();
walker.lastChilde();
walker.previousSibling();
walker.nextSibling();
Dom查找
1.不需要查找就可直接获得的元素
<html> document.documentElement
<head> document.head
<body> document.body
2.按HTML查找
id
查找:
// id查找只能用在document对象上
var elem = document.getElementById("id值");
按标签名
查找多个子元素:
// 可用在任意父元素上,不仅查找直接子元素,且查找所有后代中的元素
var elem = 任意parent.getElementsByTagName("标签名");
按name
属性查找:
// 只能用document调用
// 返回值动态集合,循环时要先用变量保存length
var elems = parent.getElementsByName("name");
按class
属性查找:
// 可在任意父元素上调用
// 不仅找直接子元素,且在所有后代中查找
// 返回动态集合,循环时要先用变量保存length
var elems = parent.getElementsByClassName("class");
3.用选择器查找
仅查找一个元素:
var elem = parent.querySelector("selector");
查找多个元素:
// 返回的是非动态集合,不会导致反复遍历DOM树
var elems = parent.querySelectorAll("selector");
// 可在任何父元素上调用
// 有浏览器的兼容性限制
getXXX vs Selector Api
执行效率:getXXX效率比SelectorAPI高
getXXX返回动态集合,不需要准备所有数据就可返回结果——快
selectorAPI,准备好所有相关数据,再返回——慢
返回值:
getXXX->动态集合,可能造成反复遍历DOM树
selectorAPI->非动态集合,不会导致反复遍历DOM树
如何选择:
如果一次getXXX查找即可找到结果时,首选getXXX
如果需要多次getXXX才能找到结果时,首选Selector API