ch10 DOM笔记

DOM

DOM(Document Object Model)文档对象模型

1.节点层次

1.1 Node类型

JavaScript中的所有节点类型都继承自Node类型。
节点类型由Node类型中定义的12种常量表示:

常量常量值代表类型
Node.ELEMENT_NODE1元素节点
Node.ATTRIBUTE_NODE2属性节点
Node.TEXT_NODE3文本节点
Node.CDATA_SECTION_NODE4
Node.ENTITY_REFERENCE_NODE5
Node.ENTITY_NODE6
Node.PROCESSING_INSTRUCTION_NODE7
Node.COMMENT_NODE8注释节点
Node.DOCUMENT_NODE9Document对象
Node.DOCUMENT_TYPE_NODE10
Node.DOCUMENT_FRAGMENT_NODE11
Node.NOTATION_NODE12

每个节点类型都有一个nodeType属性,保存以上常量值

console.log(Node.ELEMENT_NODE); //1
console.log(Node.ATTRIBUTE_NODE); //2
console.log(Node.ELEMENT_NODE == 1); //true

var htmlNode = document.documentElement; //获取html节点
//每个节点都有nodeType属性 
console.log(htmlNode.nodeType == Node.ELEMENT_NODE); //true  IE无效
console.log(htmlNode.nodeType == 1); //true 所有浏览器都可以

nodeName和nodeValue属性

nodeNamenodeValue的值完全取决于节点的类型。

节点类型nodeNamenodeValue
Node.ELEMENT_NODE标签名null
Node.DOCUMENT_NODE#documentnull
var htmlNode = document.documentElement; //获取html节点
//htmlNode的节点类型是Node.ELEMENT_NODE
console.log(htmlNode.nodeName); //HTML
console.log(htmlNode.nodeValue); //null

节点关系

每个节点都有childNodes属性,实质是一个NodeList对象(动态数组),可以通过方括号[]或者item(index)访问,该NodeList对象也有length属性。

var htmlNode = document.documentElement; //获取html节点
console.log(htmlNode.childNodes.length); //3 子节点个数,如果</head>与<body>没有换行和空格,子节点数为2
var firstChild = htmlNode.childNodes[0]; //获取第一个节点
var secondChild = htmlNode.childNodes.item(1); //获取第二个节点
console.log(firstChild.nodeType); //1 ELEMENT_NODE
console.log(secondChild.nodeType); //3 TEXT_NODE
console.log(htmlNode.childNodes.item(htmlNode.childNodes.length - 1).nodeType); //1 ELEMENT_NODE

其他常用属性:

  • parentNode父节点, 根节点的父节点为null
  • previousSibling同级中的前一个节点, 第一个节点的previousSibling为null
  • nextSibling同级中的下一个节点, 最后一个节点的nextSibling为null
  • fistChild, someNode.firstChildsomeNode.childNodes[0]等价
  • lastChild, someNode.lastChildsomeNode.childNodes[htmlNode.childNodes.length-1]等价
  • ownerDocument, 表示整个文档的文档节点
console.log(document.nodeType);//9 document为文档节点类型
console.log(htmlNode.ownerDocument == document); //true

一个常用方法:

  • hasChildNodes()
console.log(htmlNode.hasChildNodes()); //true

在这里插入图片描述

操作节点

常用的操作节点的方法有:

  • appendChild() 返回新增的节点
  • insertBefore() 返回插入的节点
  • replaceChild() 替换节点
  • removeChild() 移除节点, 返回被移除的节点
//appendChild()
var returnedNode = someNode.appendChild(newNode);
alert(returnedNode == newNode); //true
alert(someNode.lastChild == newNode); //true

//如果上面的newNode是文档的一部分,该节点会从原位置转移到新位置,原位置的节点消失

//someNode有多个子节点,appendChild将添加到最后一个节点
var returnedNode = someNode.appendChild(someNode.firstChild);
alert(returnedNode == someNode.firstChild); //false
alert(returnedNode == someNode.lastChild); //true
//insertBefore()

//插入后成为最后一个子节点
returnedNode = someNode.insertBefore(newNode, null);
alert(newNode == someNode.lastChild); //true

//插入后成为第一个子节点
returnedNode = someNode.insertBefore(newNode, someNode.firstChild);
alert(returnedNode == newNode); //true
alert(newNode == someNode.firstChild); //true

//插入到最后一个子节点前面
returnedNode = someNode.insertBefore(newNode, someNode.lastChild);
alert(newNode == someNode.childNodes[someNode.childNodes.length-2]);
//replaceChild()

//替换第一个子节点
returnedNode = someNode.replaceChild(newNode, someNode.firstChild);

//替换最后一个子节点
returnedNode = someNode.replaceChild(newNode, someNode.lastChild);
//removeChild()

//移除第一个子节点
var returnedNode = someNode.removeChild(someNode.firstChild);

//移除最后一个子节点
var returnedNode = someNode.removeChild(someNode.lastChild);

其他节点操作方法:

  • cloneNode(boolean) 创建节点的副本。如果boolean为true,则执行深复制,复制节点和子节点树;若为false,则浅复制,只复制节点本身。
  • normalize() 处理文档树中的文本节点
<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>CloneNode</title>
</head>
<body>
	<ul id="max">
		<li>item 1</li>
		<li>item 1</li>
		<li>item 1</li>
	</ul>
	<ul id="min"><li>item 1</li><li>item 1</li>	<li>item 1</li>
	</ul>

	<script>
	var maxList = document.getElementById("max");
	var deepMaxList = maxList.cloneNode(true); //深复制
	console.log(deepMaxList.childNodes.length); //7,其中三个元素节点,四个文本节点,文本节点是换行符导致的。

	var minList = document.getElementById("min");
	var deepMinList = minList.cloneNode(false); //浅复制
	console.log(deepMinList.childNodes.length); //0
	</script>
</body>
</html>

1.2 Document类型

  • JavaScript通过Document类型表示文档
  • document对象是HTMLDocument的实例,HTMLDocument继承自Document类型
  • document对象是window对象的一个属性,可以全局访问。

文档的子节点

(1)<html>

获取<html>元素节点有两种方式:

  • document对象的documentElement属性,document.documentElement
  • 通过对document对象的childNodes访问,document.childNodes[]

对于如下html文件

<html>
	<body></body>
</html>

获取<html>的方式:

var html = document.documentElement;
alert(html === document.childNode[0]); //true
alert(html === document.firstChild); //true
(2)<body>
//直接利用属性body
var body = document.body;
//也可以通过childNodes遍历访问
(3)<!DOCTYPE>

该节点类型为DocumentType, 有doctype属性访问,不过很少用,因为各个浏览器的支持不同。

var doctype = document.doctype;
<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>Document 类型</title>
</head>
<body>
	<script>
	var html = document.documentElement; //documentElement属性专指<html>
	console.log(document.childNodes.length); //2
	console.log(html === document.childNodes[1]); // true 第二个元素
	console.log(html === document.childNodes.item(1)); //true
	console.log(html === document.firstNode); //false

	var body = document.body; //专指<body>
	console.log(body);
	console.log(body === html.childNodes[2]); //true
	console.log(html.firstChild);//<head>
	console.log(html.childNodes[1]);// #text
	console.log(html.childNodes[2]);//<body>

	var doctype = document.doctype;
	console.log(doctype); // <!DOCTYPE html>
	console.log(document.firstNode); //undefined
	
	</script>
</body>
</html>

文档信息


//获取文档标题
var title = document.title;
//设置文档标题
document.title = "New Title";

//获取地址栏显示的URL
var url = document.URL;

//获取域名
var domain = document.domain;

//取得来源页面的URL
var referrer = document.referrer;

查找元素

  • getElementById(), 根据id属性值获取元素
  • getElementsByTagName(),根据标签名获取多个元素,保存在一个NodeList中。在HTML文档中,这个方法返回HTMLCollection对象,与NodeList很类似。
  • getElementsByName(), 根据元素的name属性获得元素集合,方法返回HTMLCollection对象
//getElementsByTagName()
var images = document.getElementsByTagName('img'); //返回所有的图片
alert(images.length); //图片的数量
alert(images[0].src); //第一个图片的src属性
alert(images.item(0).src) //第一个图片的src属性

// HTMLCollection的namedItem()方法,可以通过元素的name属性获得images集合中的项
<img src="myimage.gif" name='myImage'>

var myImage = images.namedItem('myImages');
//也可以采用[]访问
var myImage = images['myImages'];

//获取文档中的所有元素,传入'*'
var allElement = document.getElementByTagName('*');

特殊集合

document对象有一些特殊的集合,都是HTMLCollection对象。

  • document.anchors, 包含所有带name特性的元素
  • document.forms, 包含所有的<form>元素,与document.getElementByTagName("form")结果相同
  • document.images, 包含所有<img>元素,与document.getElementByTagName('img')结果相同

文档写入

  • write(),原样写入
  • writeln(),原样写入,结尾加换行符
  • open(),打开输出流
  • close(),关闭输出流
<!DOCTYPE html>
<head>
	<meta charset="UTF-8">
	<title>document.write() demo</title>
</head>
<body>
<p>The current date is:
	<script>
	document.write('<strong>' + (new Date()).toString() + '</strong>');
	</script>
</p>
</body>
</html>

在这里插入图片描述

在动态写入<script type="text/javascript"></script>需要注意为标签</script>需要写为<\/script>

document.write("<script type=\"text/javascript\" src=\"file.js\">" + "<\/script>")";

注意: 如果在文档加载结束后再调用document.write(),那么输出的内容将会重写整个页面。

1.3 Element类型

Element类型用于表现XML和HTML元素,提供标签名,子节点, 属性的访问。

访问元素的标签名,可以使用nodeName属性和tagName属性。

var mydiv = document.getElementById("myDiv");
console.log(mydiv.tagName); //标签名 DIV
console.log(mydiv.nodeName); //也是标签名 DIV

//默认获取到的标签名都为大写
console.log(mydiv.tagName == "div"); //false
console.log(mydiv.tagName.toLowerCase() == "div"); //true

HTML元素

每个HTML元素存在的5种标准特性(注意是特性):

  • id, 唯一标识符
  • title, 附加说明信息,一般通过工具提示条显示出来
  • lang, 元素内容的语言代码,很少使用
  • dir, 语言的方向,有’ltr’和’rtl’,很少使用
  • className,与元素的class特性对应,为元素指定的CSS类
//下面的div
<div id="myDiv" class="bd" title="Body Text" lang="en" dir="ltr"></div>

var div = document.getElementById("myDiv");
//获取五大特性
console.log(div.id); //myDiv
console.log(div.className); //bd
console.log(div.title); //Body Text
console.log(div.lang); //en
console.log(div.dir); //ltr

//设置五大特性
div.id = "youDiv";
console.log(div.id); //youDiv

操作特性

下面三个操作,可以针对任何特性,包括自定义的特性

  • getAttribute('attr')
  • setAttribute("attr", "attr-value")
  • removeAttribute("attr")

注意:一般情况下获取元素特性采用对象的属性,比如div.id,而不用div.getAttribute('id')

attributes 属性

attributes 属性的类型是 Node.ATTRIBUTE_NODE,包含一个NamedNodeMap,这是个动态集合。NamedNodeMap对象有下列方法:

  • getNamedItem(name); 返回nodeName属性等于name的节点
  • removeNamedItem(name); 移除nodeName属性等于Name的节点
  • setNamedItem(node); 向列表中添加节点
  • item(pos); 返回数字pos位置处的节点
//获取元素的id特性
var id = element.attributes.getNamedItem("id").nodeValue; 
var id = element.attributes['id'].nodeValue;

//给id设置新值
element.attributes['id'].nodeValue = 'someOtherId';

//删除属性,与removeAttribute()的效果形同
var oldAttr = element.attributes.removeNamedItem('id');
var oldAttr = element.removeAttribute('id');

//添加新特性
element.attributes.setNamedItem(newAttr);

//上述attributes方法不够方便,一般还是使用getAttribute()、setAttribute()、removeAttribute()
//不过,遍历属性可以使用attributes属性
function outputAttribute(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;
		pairs.push(attrName + '=\'' + attrValue +'\'');
	}
	return pairs.join(" ");
}

创建元素

var div = document.createElement('div'); //创建元素

div.id = 'myDiv';
div.className = 'box';

document.body.appendChild(div);// 添加到<body>中

元素的子节点

元素也支持getElementsByTagName()方法。

//html代码
<ul id='myList'>
	<li> 1 </li>
	<li> 2 </li>
	<li> 3 </li>
</ul>

//获取ul下的所有li
var ul = document.getElementById('myList');
var li = ul.getElementByTagName('li');

1.4 Text类型

Text节点有如下特征:

  • nodeType: 3,也就是Node.TEXT_NODE
  • nodeName: #text
  • nodeValue: 所包含的文本
  • parentNode: 一个Element
  • 没有子节点

通过nodeValuedata属性访问Text节点中包含的文本。通过下面几个方法可以操作节点中的文本:

  • appendData(text):将text添加到节点的末尾
  • deleteData(offset, count):从offset指定的位置开始删除count个字符
  • insertData(offset, text):从offset指定的位置插入text
  • replaceData(offset, count, text),从offset指定的位置用text替换count个字符
  • splitText(offset),从offset指定的位置将当前文本节点分成两个文本节点
  • substringData(offset, count):提取从offset指定的位置开始到offset+count为止的字符串
<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>Text类型</title>
</head>
<body>
	<div id="myDiv">Hello World!</div>

	<script>
  	//通过nodeValue或者data访问Text节点中的内容
  	var text = document.getElementById("myDiv").firstChild;
  	console.log(text.nodeValue);//Hello World!
  	console.log(text.data); //Hello World!
  	//操作节点内容
  	text.appendData("Mango");
  	console.log(text.data); //Hello World!Mango
  	text.deleteData(12, 5);
  	console.log(text.data); //Hello World!
  	text.insertData(6, "the ");
  	console.log(text.data); //Hello the World!
  	text.replaceData(6, 3, "BigBig");
  	console.log(text.data); //Hello BigBig World!
	</script>
</body>
</html>

创建文本节点

通过document.createTextNode()创建新文本节点。

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>创建文本节点</title>
	<style>
	.message {
		width: 100px;
		height: 100px;
		background-color: #333;
		color: white;
	}
	</style>
</head>
<body>
	<script>
	var myDiv = document.createElement("div");
	myDiv.className = "message";

	var textNode = document.createTextNode("Hello World");
	myDiv.appendChild(textNode);

	document.body.appendChild(myDiv);
	</script>
</body>
</html>

在这里插入图片描述

规范化文本节点

规划化文本节点的目的:使相邻的同胞文本节点合并为一个文本节点。使用normalize()方法。

<body>
	<script>
	var myDiv = document.createElement("div");
	myDiv.className = "message";
	var textNode = document.createTextNode("Hello World");
	myDiv.appendChild(textNode);
	var anotherTextNode = document.createTextNode("Mango");
	myDiv.appendChild(anotherTextNode);
	document.body.appendChild(myDiv);

	console.log(myDiv.childNodes.length); //2
	//规范化文本节点
	myDiv.normalize();
	console.log(myDiv.childNodes.length); //1
	console.log(myDiv.firstChild.nodeValue); //Hello World!Mango
	</script>
</body>

分割文本节点

使用splitText()方法。

<body>
	<script>
	var myDiv = document.createElement("div");
	myDiv.className = "message";
	var textNode = document.createTextNode("Hello World");
	myDiv.appendChild(textNode);
	document.body.appendChild(myDiv);

	console.log(myDiv.childNodes.length); //1

	var newNode = myDiv.firstChild.splitText(5);
	console.log(myDiv.firstChild.nodeValue); //"Hello"
	console.log(newNode.nodeValue); //" world"
	console.log(myDiv.childNodes.length); //2
	</script>
</body>

1.5 Comment类型

注释。先过

1.6 CDATASection类型

只针对基于XML的文档。暂时还未用到,先过。

1.7 DocumentType类型

部分浏览器支持该类型,一般不用。

DocumentType类型的对象保存在1document.doctype中。

console.log(document.doctype.name); //html

1.8 DocumentFragment类型

文档片段(document fragment)是一种“轻量级”的文档,可以包含和控制节点,不再文档树中。可以将它作为一个“仓库”使用。

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>DocumentFragment类型</title>
</head>
<body>
	<ul id="myList"></ul>
	<script>
	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);
	}
	//将fragment中的节点都转移到ul下
	ul.appendChild(fragment);
	</script>
</body>
</html>

2. DOM操作技术

2.1 动态脚本

动态脚本指的是:页面加载时不存在,但将来的某一时刻通过修改DOM动态添加的脚本。创建动态脚本的两种方式:

  • 插入外部文件
  • 直接插入JavaScript代码

比如加载如下代码:

<!-- 第一种方式:插入外部文件 -->
<script type="text/javascript" src="client.js"></script>
//动态加载
function loadScript(url){
  var script = document.createElement("script");
  script.type = "text/javascript";
  script.src = url;
  document.body.appendChild(script);
}
loadScript("client.js");
<!-- 第二种方式:行内方式 -->
<script type="text/javascript">
	function sayHi(){
      	alert("hi");
	}
</script>
//动态加载
function loadScriptString(code) {
  	var script = document.createElement("script");
  	script.type = "text/javascript";
  	try{
      	script.appendChild(document.createTextNode(code));//IE有可能抛出错误
  	} catch(ex) {
      	script.text = code;
  	}
  	document.body.appendChild(script);
}
loadScriptString("function sayHi(){alert('Hi');}");

2.2 动态样式

动态样式是指在页面刚加载时不存在的样式,在页面加载完成后动态添加到页面中。

以动态加载如下语句为例:

<link rel='stylesheet' type='text/css' href='styles.css'>
loadCSS(url) {
	var link = document.createElement('link');
    link.rel = 'stylesheet';
    link.type = 'type';
    link.href = url;
    // 将 link 标签插入到 head 标签后
    var head = document.getElementByTagName('head')[0];
    head.appendChild(link);
}
loadCSS('styles.css');

动态加载非文件式样式,如下:

<style type='text/css'>
	body {
		background-color: red
	}
</style>
var style = document.createElement("style");
style.type = "text/css";
try{
  style.appendChild(document.createTextNode("body{background-color:red}"));
} catch (ex){
  style.styleSheet.cssText = "body{background-color:red}";
}
var head = document.getElementsByTagName("head")[0];
head.appendChild(style);

2.3 操作表格

在这里插入图片描述
在这里插入图片描述

// 创建 table
var table = document.createElement('table');
table.border = 1;
table.width = '100%';

// 创建 tbody
var tbody = document.createElement('tbody');
table.appendChild(tbody);

// 创建第一行
tbody.insertRow(0);
tbody.rows[0].insertCell(0);
tbody.rows[0].cells[0].appendChild(document.createTextNode('Cell 1, 1'));
tbody.rows[0].insertCell(1);
tbody.rows[0].cells[1].appendChild(document.createTextNode('Cell 2, 1'));

// 创建第二行
tbody.insertRow(1);
tbody.rows[1].insertCell(0);
tbody.rows[1].cells[0].appendChild(document.createTextNode('Cell 1, 2'));
tbody.rows[1].insertCell(1);
tbody.rows[1].cells[1].appendChild(document.createTextNode('Cell 2, 2'));

//加入到body中
document.body.appendChild(table);

2.4 使用NodeList

理解NodeList 及其“近亲”NamedNodeMapHTMLCollection,是从整体上透彻理解DOM的关键所在。这三个集合都是“动态的”;换句话说,每当文档结构发生变化时,它们都会得到更新。
一般来说,应该尽量减少访问NodeList 的次数。因为每次访问NodeList,都会运行一次基于文档的查询。所以,可以考虑将从NodeList 中取得的值缓存起来。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值