一,基本定义
DOM是针对HTML和XML文档的API,根据W3C的HTML DOM标准,html文档中所以内容(无论是元素还是标签还是注释还是元素属性)都是节点。
二,Node类型:
每一个节点都含有一个nodeType属性,对应着不同的数字,一共有12个,这里只记住前三个:
1.代表元素节点,也是最多的
2.代表属性节点,就是元素的属性,也是节点
3.代表文本,一个空格,一个回车都是代表#text节点
9.代表document文档
如果nodeType=1,元素节点,则nodeName就是标签名,注意这里是大写的(如“DIV”),nodeValue始终是null。
注意:nodeValue和innerHTML的区别
nodeValue指的是当前节点的值,这个节点是具体的,如果只是一个元素节点,那么没有任何值,它下面的子节点的值是它子节点的nodeValue,而且这个nodeValue包括所有的内容,像换行符也会包括,不是它的,所以它为null;而innerHTML指的是该节点下所有的子节点的字符串形式,包括它们的值。
html: <div id=“aa”>
这里有一句话
</div>
js: var aa = document.getElementById(“aa”);
aa.nodeValue; //null
aa.attributes[’id’].nodeValue; // aa
aa.childNodes[0].nodeValue; // (空行)
这里有一句话
(空行)
aa.innerHTML; // 这里有一句话
每一个节点都有一个childNodes属性,它保存着一个NodeList对象(就是你取一个节点,然后打印出来,就是这个对象,对象展开下面就是该节点下面所有的子节点),可以通过childNodes[a]来访问值,这个NodeList也有length值,它是类数组,但是它不是数组,同样不可以用数组的一些迭代运算。不过它有一个特殊的方法,item(a)可以访问到里面的子节点,
例:var secondChildNode = someNode.childNodes.item(1)。访问子节点的时候要注意,如果是常规的写法,没有写在一行里,分行写的,那么每一个换行都有一个#text节点。例如:
html: <div id=“aa”>
<li></li>
<li></li>
</div>
js:
var div = document.getElementById(“aa”);
console.log(div.childNodes);
结果:
#text
li
#text
li
#text
(上面每一个都是对象,可展开的,里面就是他自身node节点属性)
如果需要把NodeList转换成数组来进行一系列的操作,可以用Array.prototype.slice()方法。不过这个方法在IE8之前无效,所以如果那样需要手动塞入:
function convertToArray(nodeList){ var array = null; try{ array = Array.prototype.slice.call(nodeList, 0); //先检测是否是IE8之前版本 } catch(ex){ array = new Array(); for(var i=0; i<nodeList.length; i++){ array.push(nodeList[i]) } } return array }
三,节点属性:
parentNode: 父节点
firstChild: 第一个子节点
lastChild: 最后一个子节点
previousSibling: 前一个兄弟节点,NodeList.firstChild的这个属性一定是null
nextSibling: 后一个兄弟节点,NodeList.lastChild的这个属性一定是null
ownerDocument: 所有的节点最后一个属性都是这个,指向当前文档节点,可以直接找到它,唯一一个
四,操作节点(带child的都是操作的子节点)
appendChild(node):向子节点的末尾添加一个节点node,添加的节点必须是定义的或者是查找出来的,不能像jquery那样手动去写字符串。
例:
var newNode = document.createElement(“div”),
newText = document.createTextNode(“hello world!”);
newNode.appendChild(newText);
someNode.appendChild(newNode);
insertBefore(a, b):在子节点b前面添加一个a节点,如果b为null,则a添加至最后,和appendChild()方法一样
replaceChild(a, b): 用a节点来替换子节点b
removeChild(node):移除子节点node
cloneNode():可以传参数true,如果不传,则为浅复制,就是只复制这个节点,而不包括它的子节点,如果传了,则为深复制,会包含该节点以及它下面的所有的子节点
五,查找元素
getElementById() //ID
getElementsByTagName() //标签名,得到数组,如果传的是”*”,则表示全部
getElementsByName() //name值
getElementsByClassName() //IE5,6,7,8中无效,所以不要用这个
上面四个都是基于document对象来查找
someNode.nameItem(name) //根据name属性值来查找
六,特性值
getAttribute()
setAttribute()
removeAttribute()
可以直接给属性赋值来修改或者设置属性值,但是注意,这里的属性一定要是内部包含的(或者本身具备的属性),而不是自定义的属性
div.id = “aa”;
div.className = “cc”;
attributes属性:
每一个节点都有这个属性,该属性后可接一些方法(nodeName全部为大写)
someNode.attributes.getNamedItem(name); //获得nodeName为name的节点,注意,这里的attribute查找是在该节点的自身里面查找,而不是子节点。
等同于:someNode.attributes[name]; //简写
someNode.attributes.removeNamedItem(name); //移除nodeName为name的节点
someNode.attributes.setNamedItem(node); //设置一个新的节点,这个用的比较少,还是用setAttribute()比较好
七,创建元素
document.createElement() //元素节点
document.createTextNode() //文本节点
八,Text类型(所有的方法都是基于文本节点,offset、count都是数字,text是字符串)
appendData(text): 将text文本添加到节点末尾
deleteData(offset, count): 从offset的位置开始删除count个字符
insertData(offset, text): 从offset的位置开始添加text
replaceData(offset, count, text): 用text来替换文本,从offset开始到offset+count结束
splitText(offset): 从offset位置将当前文本节点分成两个文本节点
substringData(offset, count): 提取从offset开始到offset+count结束的文本字符串
normalize():父节点使用这个方法,将内部的文本子节点全部合并成一个,就是字符串拼接
九,DOM操作技术
动态脚本:
function loadScript(url){ var scriptNode = document.createElement(“script”); scriptNode.src = url; scriptNode.type = “text/javascript”; document.body.appendChild(scriptNode); }
动态样式:
function loadScript(url){ var cssNode = document.createElement(“link”); cssNode.href = url; cssNode.type = “text/css”; cssNode.rel = “stylesheet”; document.getElementsByTagName(“head”)[0].appendChild(cssNode); }
=======================
DOM扩展:
1,选择器
querySelector(): 类似于jquery的选择器,传入的css选择符
querySelectorAll(): 也是传入css选择符,只不过返回的是所有的匹配到的,一个数组,相当于NodeList
2,元素遍历:
由于之前的childNodes包含文本节点、注释节点等,不利于我们去查找获取子节点,所以推出了新的API:
childElementCount: 获取子节点的个数(只是元素节点)
firstElementChild: 第一个元素子节点
lastElementChild: 最后。。。。
previousElementSibling: 。。。。
nextElementSibling: 。。。。
3,classList属性(返回的是一个DOMTokenList对象,这个对象的结构类似于这样:
{
0: ‘class1’,
1: ‘class2’,
2: ‘class3’,
value: ‘class1 class2 class3’
}
):
elementNode(元素节点).classList.add(value); 添加value类,如果有就不添加了
elementNode(元素节点).classList.contains(value); 列表中是否存在这个值,如果存在返回true,否则false
elementNode(元素节点).classList.remove(value); 删除value类
elementNode(元素节点).classList.toggle(value); 如果列表中有,就删除,没有就添加
4,焦点
focus();
document.hasFocus(); 判断文档是否获得焦点
5,document.head,目前只有Safari 5和谷歌浏览器能用,所以还是用getElementsByTagName方法
6,自定义属性
html5为元素添加自定义属性的时候,一定要用 data- 开头,目的是提供语义信息,如果要访问这个属性值,不能用div.data-myname,会报错,只能用dataset,后面跟的是 data- 后面的myname,
div.dataset.myname = 123; 设置自定义属性值
7,innderHTML属性
返回子节点所有的内容,包括元素、注释、文本,但是IE和Opera返回的是大写的,所以不同的浏览器返回的也不同。不是所有的元素都有这个属性,像table相关的都不支持这个。
8,outerHTML
返回的是包含当前节点的所有内容
9,insertAdjacentHTML()方法,两个参数
element.insertAdjacentHTML(“beforebegin”, “<p>hello</p>”); //作为前一个同辈元素插入,就是同级
element.insertAdjacentHTML(“afterbegin”, “<p>hello</p>”); //作为第一个子元素插入,是在子节点里面
element.insertAdjacentHTML(“beforeend”, “<p>hello</p>”); //作为最后一个子元素插入,也是在子节点里面
element.insertAdjacentHTML(“afterend”, “<p>hello</p>”); //作为后一个同辈元素插入
10,scrollIntoView(); // 项目中遇到的做城市列表选择右侧的首字母跳转功能
someNode.scrollIntoView(); //如果不传参数或者传true,默认节点的顶端与视口顶部平行,如果传false,默认节点的底部与视口顶部平行
11,children属性:
和childNodes差别,children只包含元素子节点,IE9以后是只包含元素节点,IE8及之前也包含注释节点
12,contains(someNode):检测某节点下是否包含此子节点
DOM3级,类似方法:compareDocumentPosition(someNode),返回值
1 //无关
2 //居前(在参考节点之前)
4 //居后
8 //包含(给定节点是参考节点的祖先)
16 //被包含(是子节点,等同于contains)
13,innerText,Firefox不支持,
和innerHTML区别,一个返回的是纯文本,不包含元素节点标签等,一个返回的html代码,包含所有节点
14,outerText
div.outerText = “hello world”;
等同于
var text = document.createTextNode(“hello world”)
div.parentNode.replaceChild(text, div)
=======================
DOM2和DOM3
DOM1级主要定义的是HTML和XML文档的底层结构,DOM2和DOM3则在这个结构的基础上引入了更多的交互能力,也支持了更高级的XML特性。
获得浏览器视口大小:
function getViewPort(){ if (document.compatMode == 'BackCompat') { return { width: document.body.clientWidth, height: document.body.clientHeight } } else { return { width: document.documentElement.clientWidth, height: document.documentElement.clientHeight } } }
监测某元素是否在顶部,如果不是就使其滚到顶部
function scrollToTop(element){ if (element.scrollTop != 0) { element.scrollTop = 0 } }