第十章 DOM
第十章 DOM
- DOM文档对象模型 是针对HTML和XML文档的一个API(应用程序编程接口)
- IE中所有DOM对象都是以COM对象实现的,与原生JS对象的行为或活动特点并不一致
10.1 节点层次
- 文档节点是每个文档的根节点
- 称为元素,是文档的最外层元素
10.1.1 Node类型
- DOM1级定义了一个Node接口,由DOM中的所有节点类型实现
- 这个Node接口在JS中是作为Node类型实现的,除IE所有浏览器可访问到这个类型
- 任何节点类型必居其一:
NodeType | Named Constant |
---|---|
1 | ELEMENT_NODE |
2 | ATTRIBUTE_NODE |
3 | TEXT_NODE |
4 | CDATA_SECTION_NODE |
5 | ENTITY_REFERENCE_NODE |
6 | ENTITY_NODE |
7 | PROCESSING_INSTRUCTION_NODE |
8 | COMMENT_NODE |
9 | DOCUMENT_NODE |
10 | DOCUMENT_TYPE_NODE |
11 | DOCUMENT_FRAGMENT_NODE |
12 | NOTATION_NODE |
var someNode = document.getElementById('test');
if(someNode.nodeType == 1){ //适用于所有浏览器
console.log("Node is an element");
}
nodeName nodeValue
//<p id="test">aaa</p>
var someNode = document.getElementById('test');
if(someNode.nodeType == 1){
//适用于所有浏览器
console.log(someNode.nodeName); //元素标签名 P
console.log(someNode.nodeValue);//null
}
节点关系
- 每个节点都有childNodes属性,其中保存着NodeList类数组对象
- NodeList是有生命,可呼吸的对象,并非在第一次访问它们某个瞬间拍下的快照
- 访问方法
var firstChild = someNode.childNodes[0]; //推荐
var secondChild = someNode.childNodes.item(1);
var count = someNode.childNodes.length;
- NodeList转换成数组
function convertToArray(nodes){
var array = null;
try{
array = Array.prototype.slice.call(nodes, 0);
}catch(ex){
//兼容IE8
array = new Array();
for(var i=0, len=nodes.length; i < len; i++){
array.push(nodes[i]);
}
}
return array;
}
-
常见属性 无值时为null
- parentNode
- childNodes[n]
- previousSibling
- nextSibling
- fisrstChild
- lastChild
- ownerDocument 直接回溯到顶端文档节点
- childNodes.length
-
常用方法
- hasChildNodes()
操作节点
- appendChild() 如果插入自身拥有的节点,相当于调换了顺序
<div class="box" id="box">
<div class="box_1">
<div class="box_1_1">box_1_1</div>
<div class="box_1_2">box_1_2</div>
<div class="box_1_3">box_1_3</div>
</div>
<div class="box_2">
<div class="box_2_1">box_2_1</div>
<div class="box_2_2">box_2_2</div>
<div class="box_2_3">box_2_3</div>
</div>
<div class="box_3">
<div class="box_3_1">box_3_1</div>
<div class="box_3_2">box_3_2</div>
<div class="box_3_3">box_3_3</div>
</div>
</div>
var someNode = document.getElementById('box');
var newNode = document.createElement('div');
newNode.innerText = '新增节点';
var returnedNode = someNode.appendChild(newNode);
var returnedNode = someNode.appendChild(someNode.firstChild);
console.log(returnedNode == someNode.firstChild); //false
console.log(returnedNode == someNode.lastChild); //true
- insertBefore(新节点,旧参照位置节点)
var returnedNode = someNode.insertBefore(newNode, someNode.firstChild); //最前
var returnedNode = someNode.insertBefore(newNode, null); //最后
- replaceChild 替换节点
var returnedNode = someNode.replaceChild(newNode, someNode.firstChild);
- removeChild 移除节点
var returnedNode = someNode.removeChild(someNode.firstChild);
其他方法
- cloneNode()
- 传入true进行深复制 会复制节点及其整个子节点树
- 不传入时仅复制本身
- normalize() 处理文档树中的文本节点
- 解析器可能出现文本节点不含文本 或出现两个文本节点
- 调用这个方法可以删除空文本节点 或合并相邻为一个文本节点
10.1.2 Document类型
- JS通过Document类型表示文档
- 在浏览器中 document对象是HTMLDocument(继承自Document类型)的一个实例,表示整个HTML页面
- document对象是window对象的一个属性,可以作为全局对象访问
- document节点特征
- nodeType: 9
- nodeName: "#document"
- nodeValue: null
- parentNode: null
- ownerDocument null
- 子节点可能是:DocumentType Element ProcessingInstruction Comment
文档的子节点
- document.documentElement 取得对的引用
- document.childNodes[n]
- document.firstChild
- document.body
- document.doctype //取得对<!DOCTYPE>的引用 浏览器的支持差别很大
文档信息
- 作为HTMLDocument的一个实例,document对象还有一些标准Document对象所没有的属性
- title
var originalTitle = document.title;
document.title = "New title";
- URL 完整URL
- domain 域名
- referrer 来源页面的URL
//假设页面雷子phone.baidu.com域
document.domain = "baidu.com"; //成功 子级可访问父级
document.domain = "taobao.com"; //失败 不能设置url中不包含的域
查找元素 (最常见)
- getElementById(id)
- 严格匹配id 区分大小写
- IE7怪癖:如果表单元素id和name相同 则该方法会返回元素而非元素引用
- getElementsByTagName()
- 返回HTMLCollection对象动态集合 和NodeList类似
// <img src="myimg.gif" name="myImg">
var images = document.getElementsByTagName("img");
console.log(images.length);
console.log(images[0].src);
console.log(images.item(0).src);
var myImg = images.namedItem("myImg");
var myImg = images["myImg"];
//返回所有元素 IE会包含注释
document.getElementsByTagName("*");
- getElementsByName()
- HTMLDocument类型才有的方法 返回给定name特性的所有元素
- 一般取单选按钮
特殊集合
- 都是HTMLCollection对象 集合项目会动态变化
- document.anchors 包含文档中所有带name特性的a元素
- document.links 包含文档中所有带href特性的a元素
- document.forms 包含文档中所有form元素 等于 document.getElementsByTagName("form")
- document.images 包含文档中所有form元素 等于 document.getElementsByTagName("img")
DOM一致性检测
- DOM分多级 含有多个部分,所以需要检测实现了DOM的哪些部分
- 最好除了检测hasFeature()之外 还同时使用能力检测
var hasXmlDom = document.implementation.hasFeature("XML","1.0");
文档写入
- document.write()
- document.writeln()
- document.open()
- document.close()
10.1.3 Element类型(最常见之一)
- 提供对元素标签名、子节点及特性的访问
- Element类型具有以下特征
- nodeType为1
- nodeName为元素标签名
- nodeValue为null
- parentNode可能是Document或Element
- 访问元素标签名 可以使用nodeName 也可以使用tagName
//<div id="mydiv">test</div>
var div = document.getElementById("mydiv");
console.log(div.tagName); //DIV
console.log(div.tagName == div.nodeName); //true
- 一般使用
element.tagName.toLowerCase() == "div"
HTML元素
- id title className
- lang dir
var div = document.getElementById("mydiv");
console.log(div.id); //mydiv
div.title = "somediv";
取得特性
getAttribute()
- 注意
- 特性名要与实际相同 如element.getAttribute("class") 而非className
- 不存在返回null
- 不区分大小写
- H5规范里 自定义特性应该加上
data-
前缀
- 两类特殊特性
- style
- console.log(div.style); //返回对象
- console.log(div.getAttribute('style')); //返回文本
- onclick
- 属性访问 返回函数或null
- getAttribute访问 返回字符串
- style
setAttribute()
- div.setAttribute("id", "someId");
- div.setAttribute("data-show", "false"); //自定义特性会自动转小写
- 如果通过对象形式添加自定义属性 则不会自动成为元素特性
removeAttribute()
attributes属性
- 比较少用 可以遍历
function outputAttributes(element){
var pairs = new Array(),
attrName,
attrValue,
i,
len;
for (i=0, len=element.attributes.length; i < len; i++){
attrName = element.attributes[i].nodeName;
attrValue = element.attributes[i].nodeValue;
if (element.attributes[i].specified){
pairs.push(attrName + "=\"" + attrValue + "\"");
}
}
return pairs.join(" ");
}
创建元素
- document.createElement("div");
元素的子节点
for(var i=0, len=element.childNodes.length; i<len;i++){
if(element.childNodes[i].nodeType == 1){
//...
}
}
var ul = document.getElementById("myList");
var items = ul.getElementsByTagName("li");
10.1.4 Text类型
- 纯文本内容 可以包含转义后的HTML字符
- 具有以下特征
- nodeType为3
- nodeName为"#text"
- nodeValue为所包含的文本
- parentNode是一个Element
- 不支持子节点
修改 element.firstChild.NodeValue="xxx"
创建 document.createTextNode()
规范 element.normalize()
分割 element.splitText()
10.1.5 Comment类型:注释
- 创建
document.createComment()
10.1.6 CDATASection类型
- 只针对XML
10.1.7 DocumentType类型
- 包含文档doctype所有信息
10.1.8 DocumentFragment类型
- 轻量级文档 可以作为临时仓库使用
function addItems(){
var fragment = document.createDocumentFragment();
var ul = document.getElementById("myList");
var li = null;
for (var i=0; i < 3; i++){
li = document.createElement("li");
li.appendChild(document.createTextNode("Item " + (i+1)));
fragment.appendChild(li);
}
ul.appendChild(fragment);
}
10.1.9 Attr类型
10.2 DOM操作技术
10.2.1 动态脚本
- 加载外部JS文件是异步的
var script = document.createElement("script");
script.type = "text/javascript";
script.src = "client.js";
document.body.appendChild(script);
<body>
<p>You should see an alert saying "hi" after clicking the button.</p>
<input type="button" value="Add Script" onclick="addScript()">
<script type="text/javascript">
function loadScriptString(code){
var script = document.createElement("script");
script.type = "text/javascript";
try {
script.appendChild(document.createTextNode(code));
} catch (ex){
script.text = code;
}
document.body.appendChild(script);
}
function addScript(){
loadScriptString("function sayHi(){alert('hi');}");
sayHi();
}
</script>
</body>
10.2.2 动态样式
- 加载外部样式文件是异步的
var link = document.createElement("link");
link.rel = "stylesheet";
link.type = "text/css";
link.href = "style.css";
var head = document.getElementByTagName("head")[0];
head.appendChild(link);
function loadStyleString(css){
var style = document.createElement("style");
style.type = "text/css";
try{
style.appendChild(document.createTextNode(css));
} catch (ex){
style.styleSheet.cssText = css;
}
var head = document.getElementsByTagName("head")[0];
head.appendChild(style);
}
function addStyle(){
loadStyleString("body{background-color:red}");
}
10.2.3 操作表格
- [拓展] 10.2.3 JS操作表格常用方法
tbody.insertRow(0);
10.2.4 使用NodeList
- 近亲:NamedNodeMap、HTMLCollection
- 动态更新