什么是DOM?
DOM(Document Object Model --- 文档对象模型):是针对HTML和XML文档的一个API(应用程序编程接口)。
DOM定义了表示和修改文档所需的方法。DOM对象即为宿主对象,由浏览器厂商定义,用来操作html 和 xml 功能的一类对象的集合。也有人称DOM是对HTML以及XML的标准编程接口。
DOM开始一切生成的组都是类数组。
DOM节点的增删改查
查(查看元素节点):
document代表整个文档
docment.getElementByld("id"); 通过 id 查找 HTML 元素。
元素id在ie8以下的浏览器,不区分id大小写,而且也返回匹配name属性的元素。
// 通过 id 查找 HTML 元素
var divId = document.getElementById("Id");
divId.style.width = "100px";
divId.style.height = "100px";
divId.style.backgroundColor = "red";
divId.style.color = "#fff";
getElementsByTagName(“tab”); 通过标签名查找 HTML 元素。(推荐使用)
// 通过标签名查找 HTML 元素
var divTab = document.getElementsByTagName("div")[0];
divTab.style.width = "100px";
divTab.style.height = "100px";
divTab.style.backgroundColor = "green";
divTab.style.color = "#fff";
getElementsByClassName("class"); 通过类名查找 HTML 元素。
ie8 和 ie8以下的ie版本中没有,可以多个class一起。
// 通过类名查找 HTML 元素
var divClass = document.getElementsByClassName("Class")[0];
divClass.style.width = "100px";
divClass.style.height = "100px";
divClass.style.backgroundColor = "#000";
divClass.style.color = "#fff";
getElementsByName("name"); 通过name属性查找 HTML 元素。
需注意,只有部分标签name可生效(表单,表单元素,img,iframe)。
// 通过name属性查找 HTML 元素
var divName = document.getElementsByName("Name")[0];
divName.style.width = "100px";
divName.style.height = "100px";
divName.style.backgroundColor = "#000";
divName.style.color = "#fff";
querySelector("#id / .class / tab"); 通过 CSS 选择器查找 HTML 元素。(选择一个)
在ie7 和 ie7以下的版本中没有 ---> 静态的,没有实时性。所以不用它。 (css怎么选这里就可以怎么选)
// 通过 CSS 选择器查找 HTML 元素
var divId = document.querySelector("#Id");
divId.style.width = "100px";
divId.style.height = "100px";
divId.style.backgroundColor = "#000";
divId.style.color = "#fff";
querySelectorAll("#id / .class / tab"); 通过 CSS 选择器查找 HTML 元素。(选择一组)
在ie7 和 ie7以下的版本中没有 ---> 静态的,没有实时性。所以不用它。 (css怎么选这里就可以怎么选)
p元素
// 通过 CSS 选择器查找 HTML 元素
var divClass = document.querySelectorAll(".Class")[1];
divClass.style.width = "100px";
divClass.style.height = "100px";
divClass.style.backgroundColor = "#000";
divClass.style.color = "#fff";
遍历节点树
DOM可以将任何HTML或XML文档描绘成一个由多层节点构成的结构。
parentNode ---> 父亲点(最顶端的parentNode为#document); (有document)
childNodes ---> 子节点们
firstChild ---> 第一个子节点
lastChild ---> 最后一个子节点
nextSibling ---> 后一个兄弟节点
previousSibling ---> 前一个兄弟节点
1
第一个子节点
123
最后一个子节点
// 通过 CSS 选择器查找 HTML 元素
var divClass = document.getElementsByClassName("Class")[0];
// 父节点
console.log(divClass.parentNode); //
// 子节点们
console.log(divClass.childNodes); // NodeList(3) [text, p, text]
// 第一个子节点
console.log(divClass.firstChild); // 第一个子节点
// 最后一个子节点
console.log(divClass.lastChild); // 最后一个子节点
// 后一个兄弟节点
console.log(divClass.nextSibling); // 2
// 前一个兄弟节点
console.log(divClass.previousSibling); //
1
节点
节点分为几种不同的类型,每种类型分别表示文档中不同的信息及标记。
元素节点 ———— 1
属性节点 ———— 2 没啥用
文本节点 ———— 3
注释节点 ———— 8
document ———— 9
DocumentFragment ———— 11
获取节点类型使用nodeType属性。
基于元素节点树的遍历
parentElement ---> 返回当前元素的父元素节点(IE不兼容) html的元素父节点不是document
children ---> 只返回当前元素的元素子节点
node.childElementCount === node.children.length 当前元素节点的子元素节点个数(IE不兼容)
firstElementChild ---> 返回的是第一个元素节点(IE不兼容)
lastElementChild ---> 返回的是最后一个元素节点(IE不兼容)
nextElementSibling / previousElementSibling ---> 返回后一个 / 前一个兄弟元素节点(IE不兼容)
1
第一个子节点
123
最后一个子节点
2
// 通过 CSS 选择器查找 HTML 元素
var divClass = document.getElementsByClassName("Class")[0];
// 父元素
console.log(divClass.parentElement); //
// 元素子节点
console.log(divClass.children); // HTMLCollection [p]
// 子元素节点个数
console.log(divClass.childElementCount); // 1
// 子元素节点个数
console.log(divClass.children.length); // 1
// 第一个元素节点
console.log(divClass.firstElementChild); //
123
// 最后一个元素节点
console.log(divClass.lastElementChild); //
123
// 后一个兄弟元素节点
console.log(divClass.nextElementSibling); // 2
// 前一个兄弟元素节点
console.log(divClass.previousElementSibling); //
1
元素节点
节点的四个属性:
nodeName 元素的标签名,以大写形式表示,只读
nodeValue Text节点或Comment节点的文本内容,可读写
nodeType 该节点的类型,只读
attributes Element节点的属性集合
// 返回元素的直接子元素节点
var div = document.getElementsByTagName('div')[0];
function retElementChild(node) {
// no children
var temp = {
// 建立类数组
length: 0,
push: Array.prototype.push,
splice: Array.prototype.splice
},
child = node.childNodes,
len = child.length;
for (var i = 0; i < len; i++) {
// 判断node的子节点是不是元素节点
if (child[i].nodeType === 1) {
temp.push(child[i]);
}
}
return temp;
}
console.log(retElementChild(div));
返回元素的直接子元素节点
节点的一个方法(每个节点都有) Node.hasChildNodes(); ---》 检查元素有没有子节点,返回true/false。
dom结构树
---> Document(文档) ---> HTMLDocument
---> CharacterData ---> Text
Node ---> Comment
---> Element(文档中的元素) ---> HTMLElement ---> HTMLHeadElement HTMLBodyElement HTMLTitleElement HTMLParagraphElement HTMLInputElement HTMLTableElement
---> Attr ...etc...
HTMLDocument是document的原型,HTMLDocument的原型是Document。
继承关系:document ---> HTMLDocument.prototype ---> Document.prototype。
getElementById 方法定义在Document.prototype上,即Element节点上不能使用。
getElementsByName 方法定义在HTMLDocument.prototype上,即非html中的document不能使用(xml document.Element)。
getElementsByTagName 方法定义在Document.prototype和Element.prototype上。 常见方法 里面写* 相当于选择所有标签,按通配符来选择。
HTMLDocument.prototype 定义了一些常用属性,body.head 分别指代HTML文档中的body 和 head标签。 直接使用 document.body document.head。
Document.prototype 上定义了documentElement属性,指代文档的根元素,在HTML文档中,它总是指代html元素。 直接使用 document.documentElement 选中的就是html。
getElementsByClassName、querySelectorAll、querySelector 在Document.prototype,Element.prototype类中均有定义。 两头都能使用
增
document.createElement(); 创建元素节点 (最常见)
document.createTextNode(); 创建文本节点
document.createComment(); 创建注释节点
var div = document.createElement('div'); // 在js里面
document.body.appendChild(div); // 在body里面加入div
var text = document.createTextNode('文本节点'); // 创建文本节点
var Div = document.getElementsByTagName("div")[0];
Div.appendChild(text); // 在div里面加入text
var comment = document.createComment('this is comment'); // 创建注释节点
Div.appendChild(comment); // 在div里面加入comment
创建节点
document.createDocumentFragment(); 创建文档碎片节点
插 (都常见)
PARENTNODE.appendChild(); 任何一个元素节点都有这个appendChild方法。 ---> 相当于push 剪切操作
var div = document.createElement('div'); // 在js里面
document.body.appendChild(div); // 在body里面加入div
var text = document.createTextNode('文本节点'); // 创建文本节点
var Div = document.getElementsByTagName("div")[0];
Div.appendChild(text); // 在div里面加入text
document.body.appendChild(text);
var comment = document.createComment('this is comment'); // 创建注释节点
Div.appendChild(comment); // 在div里面加入comment
appendChild
PARENTNODE.insertBefore(a, b); insert -- a, before -- b。 a 在 b 之前被插入。
var div = document.getElementsByTagName('div')[0];
var span = document.createElement('span');
var strong = document.createElement('strong');
var i = document.createElement('i');
div.appendChild(span);
div.appendChild(strong);
div.appendChild(i);
div.insertBefore(strong, span);
div.insertBefore(i, span);
insertBefore
删 (全都用)
parent.removeChild(); 谋杀式 ---》 父节点删除子节点 (剪切出来)
var div = document.getElementsByTagName('div')[0];
var span = document.getElementsByTagName('span')[0];
var strong = document.getElementsByTagName('strong')[0];
var i = document.getElementsByTagName('i')[0];
var ii = div.removeChild(i);
console.log(ii); //
removeChild
child.remove(); 自杀式es5.0 ---》 自己调用一个方法删除自己 (真正销毁)
var div = document.getElementsByTagName('div')[0];
var span = document.getElementsByTagName('span')[0];
var strong = document.getElementsByTagName('strong')[0];
var i = document.getElementsByTagName('i')[0];
i.remove();
remove
替换
parent.replaceChild(new, origin); 表示拿新的元素替换旧的元素。 (旧的被剪切出来了)
var div = document.getElementsByTagName('div')[0];
var span = document.getElementsByTagName('span')[0];
var strong = document.getElementsByTagName('strong')[0];
var i = document.getElementsByTagName('i')[0];
var p = document.createElement('p');
div.replaceChild(p, i);
replaceChild
Element节点
Element节点的一些属性
innerHTML (可以写入,覆盖式 = , 追加 +=)
123
var div = document.getElementsByTagName('div')[0];
console.log(div.innerHTML); // 把div里面的html内容取出来
div.innerHTML = "写入文本";
div.innerHTML += " + 追加文本";
innerHTML
innerText(老版本火狐不兼容)/textContent(老版本IE不好使) 火狐支持textContent 和 innerText 一样
123
var div = document.getElementsByTagName('div')[0];
console.log(div.innerText); // 123
div.innerText = "写入文本";
div.innerText += " + 追加文本";
innerText
Element节点的一些方法
ele.setAttribute(); 给元素设置行间属性
ele.getAttribute(); 取出设置的属性的属性值
// 设置行间属性
var div = document.getElementsByTagName('div')[0];
div.setAttribute('class', 'demo'); // 属性名 + 属性值
// 取出设置的属性的属性值
var div = document.getElementsByTagName('div')[0];
console.log(div.getAttribute('class')); // demo
行间属性
面试题
1. 遍历元素节点树(在原型链上编程)
// 返回元素的直接子元素节点
var div = document.getElementsByTagName('div')[0];
function retElementChild(node) {
// no children
var temp = {
length: 0,
push: Array.prototype.push,
splice: Array.prototype.splice
},
child = node.childNodes,
len = child.length;
for (var i = 0; i < len; i++) {
if (child[i].nodeType === 1) {
temp.push(child[i]);
}
}
return temp;
}
console.log(retElementChild(div));
2. 封装函数,返回元素e的第n层祖先元素节点
function retParent(elem, n) {
while(elem && n) {
elem = elem.parentElement;
n --; // n 为 0 跳出循环
}
return elem;
}
var i = document.getElementsByTagName('i')[0];
// retParent(元素, 第几层)
3. 封装函数,返回元素e的第n个兄弟元素节点,n为正,返回后面的兄弟元素节点,n为负,返回前面的,n为0,返回自己。
function retSibling(e, n) {
while(e && n) {
if(n > 0) {
// e = e.nextElementSibling;
if(e.nextElementSibling) {
e = e.nextElementSibling;
}else{
// 没有下一个兄弟元素节点,找下一个兄弟节点,返回下一个兄弟节点
for(e = e.nextSibling; e && e.nodeType != 1; e = e.nextSibling);
}
n --;
}else{
// e = e.previousElementSibling;
if(e.previousElementSibling) {
e = e.previousElementSibling;
}else{
for(e = e.previousSibling; e && e.nodeType != 1; e = e.previousSibling);
}
n ++;
}
}
return e;
}
var strong = document.getElementsByTagName('strong')[0];
4. 编辑函数,封装myChildren功能,解决以前部分浏览器的兼容性问题。
abc
Element.prototype.myChildren = function () {
var child = this.childNodes;
var len = child.length;
var arr = [];
for(var i = 0; i < len; i ++) {
if(child[i].nodeType == 1) {
arr.push(child[i]);
}
}
return arr;
}
var div = document.getElementsByTagName('div')[0];
5. 自己封装hasChildren()方法,不可用children属性。
abc
Element.prototype.hasChildren = function () {
var child = this.childNodes;
var len = child.length;
var arr = [];
for (var i = 0; i < len; i++) {
if (child[i].nodeType == 1) {
return true;
}
}
return false;
}
var div = document.getElementsByTagName('div')[0];
6. 请编写一段代码JavaScript脚本生成下面这段DOM结构。要求:使用标准的DOM方法或属性。
1233444
提示 dom.className 可以读写class。
var div = document.createElement('div');
var p = document.createElement('p');
div.setAttribute('class', 'example');
p.setAttribute('class', 'slogan');
var text = document.createTextNode('1233444');
p.appendChild(text);
div.appendChild(p);
document.body.appendChild(div);
7. 封装函数insertAfter();功能类似insertBefore();
提示:可忽略老版本浏览器,直接在Element.prototype上编程。
Element.prototype.insertAfter = function (targetNode, afterNode) {
var beforeNode = afterNode.nextElementSibling;
if(beforeNode == null) {
this.appendChild(targetNode);
}else{
this.insertBefore(targetNode,beforeNode);
}
}
var div = document.getElementsByTagName('div')[0];
var b = document.getElementsByTagName('b')[0];
var span = document.getElementsByTagName('span')[0];
var p = document.createElement('p');
8. 将目标节点内部的节点顺序逆序。 --- 使用appendChild()
eg:
Element.prototype.invertedChild = function () {
var child = this.children;
len = child.length;
for (var i = len - 2; i >= 0; i--) {
this.appendChild(child[i]);
}
return this;
}
var div = document.getElementsByTagName('div')[0];
div.invertedChild();