JavaScript DOM
来源:互联网 发布:php base64 编辑:程序博客网 时间:2024/05/29 17:48
DOM(Document Object Model)即文档对象模型,针对 HTML 和 XML 文档的 API(应用程序接口) 。DOM 描绘了一个层次化的节点树,运行开发人员添加、移除和修改页面的某一部分。DOM 脱胎于 Netscape 及微软公司创始的 DHTML(动态 HTML) ,但现在它已经成为表现和操作页面标记的真正跨平台、语言中立的方式。
第1章 DOM综述
DOM概述
DOM 中的三个字母:
- D(文档)可以理解为整个 Web 加载的网页文档;
- O(对象)可以理解为类似 window 对象之类的东西,可以调用属性和方法,这里我们说的是 document对象;
- M(模型)可以理解为网页文档的树型结构。
DOM 有三个等级,分别是 DOM1、DOM2、DOM3,并且 DOM1 在 1998 年 10 月成为W3C 标准。DOM1 所支持的浏览器包括 IE6+、Firefox、Safari、Chrome 和 Opera1.7+。
PS:IE 中的所有 DOM 对象都是以 COM 对象的形式实现的,这意味着 IE 中的 DOM可能会和其他浏览器有一定的差异。
节点
加载 HTML 页面时,Web 浏览器生成一个树型结构,用来表示页面内部结构。DOM 将这种树型结构理解为由节点组成。
节点树
从上图的树型结构,我们理解几个概念,html 标签没有父辈,没有兄弟,所以 html 标签为根标签。head 标签是 html 子标签,meta 和 title 标签之间是兄弟关系。如果把每个标签当作一个节点的话,那么这些节点组合成了一棵节点树。
PS:后面我们经常把标签称作为元素,是一个意思。
节点种类
元素节点、文本节点、属性节点。
- 元素节点
- 属性节点
- 文本节点
< div title=”属性节点”>测试 Div< /div>
第2章 查找节点
W3C 提供了比较方便简单的定位节点的方法和属性, 以便我们快速的对节点进行操作 。
分别为:
- getElementById()
- getElementsByTagName()
- getElementsByName()
- getAttribute()
- setAttribute()
- removeAttribute()
元素节点方法
getElementById()
getElementById()方法,接受一个参数:获取元素的 ID。如果找到相应的元素则返回该元素的 HTMLDivElement 对象,如果不存在,则返回 null。
document.getElementById('box'); //获取 id 为 box 的元素节点
PS:上面的例子,默认情况返回 null,这无关是否存在 id=”box”的标签,而是执行顺序问题。解决方法:
- 把 script 调用标签移到 html 末尾即可;
- 使用 onload 事件来处理 JS, 等待 html 加载完毕再加载 onload 事件里的 JS。
window.onload = function () { //预加载 html 后执行 document.getElementById('box');};
PS:id 表示一个元素节点的唯一性,不能同时给两个或以上的元素节点创建同一个命名的 id。某些低版本的浏览器会无法识别 getElementById()方法,比如 IE5.0-,这时需要做一些判断,可以结合上章的浏览器检测来操作。
if (document.getElementById) { //判断是否支持 getElementById alert('当前浏览器支持 getElementById');}
当我们通过 getElementById()获取到特定元素节点时, 这个节点对象就被我们获取到了 ,而通过这个节点对象,我们可以访问它的一系列属性。
getElementsByTagName()
getElementsByTagName()方法将返回一个对象数组HTMLCollection(NodeList),这个数组保存着所有相同元素名的节点列表。
document.getElementsByTagName('*'); //获取所有元素
**PS:IE 浏览器在使用通配符的时候,会把文档最开始的 html 的规范声明当第一个元素节点。**
document.getElementsByTagName('li'); //获取所有 li 元素,返回数组document.getElementsByTagName('li')[0]; //获取第一个 li 元素,HTMLLIElementdocument.getElementsByTagName('li').item(0) //获取第一个 li 元素,HTMLLIElementdocument.getElementsByTagName('li').length; //获取所有 li 元素的数目
PS:不管是 getElementById 还是 getElementsByTagName,在传递参数的时候,并不是所有浏览器都必须区分大小写, 为了防止不必要的错误和麻烦, 我们必须坚持养成区分大小写的习惯。
getElementsByName()
getElementsByName()方法可以获取相同名称(name)的元素,返回一个对象数组HTMLCollection(NodeList)。
document.getElementsByName('add') //获取 input 元素document.getElementsByName('add')[0].value //获取 input 元素的 value 值document.getElementsByName('add')[0].checked//获取 input 元素的 checked 值
PS:对于并不是 HTML 合法的属性,那么在 JS 获取的兼容性上也会存在差异,IE 浏览器支持本身合法的 name 属性,而不合法的就会出现不兼容的问题。
getAttribute()方法
getAttribute()方法将获取元素中某个属性的值。它和直接使用.属性获取属性值的方法有一定区别。
document.getElementById('box').getAttribute('id');//获取元素的 id 值document.getElementById('box').id; //获取元素的 id 值document.getElementById('box').getAttribute('mydiv');//获取元素的自定义属性值document.getElementById('box').mydiv //获取元素的自定义属性值, 非 IE 不支持document.getElementById('box').getAttribute('class');//获取元素的 class 值,IE 不支持document.getElementById('box').getAttribute('className');//非 IE 不支持
PS:HTML 通用属性 style 和 onclick,IE7 更低的版本 style 返回一个对象,onclick 返回一个函数式。虽然 IE8 已经修复这个 bug,但为了更好的兼容,开发人员只有尽可能避免使用 getAttribute()访问 HTML 属性了,或者碰到特殊的属性获取做特殊的兼容处理。
setAttribute()
setAttribute()方法将设置元素中某个属性和值。它需要接受两个参数:属性名和值。如果属性本身已存在,那么就会被覆盖。
document.getElementById('box').setAttribute('align','center');//设置属性和值document.getElementById('box').setAttribute('bbb','ccc');//设置自定义的属性和值
PS:在 IE7 及更低的版本中,使用 setAttribute()方法设置 class 和 style 属性是没有效果的,虽然 IE8 解决了这个 bug,但还是不建议使用。
removeAttribute()
removeAttribute()可以移除 HTML 属性。
document.getElementById('box').removeAttribute('style');//移除属性
PS:IE6 及更低版本不支持 removeAttribute()方法。
第3章 节点的属性
node节点属性
节点可以分为元素节点、属性节点和文本节点,而这些节点又有三个非常有用的属性 ,分别为:nodeName、nodeType 和 nodeValue。
信息节点属性
document.getElementById('box').nodeType; //1,元素节点
元素节点的属性
document.getElementById('box').tagName; //DIVdocument.getElementById('box').innerHTML; //测试 Div
HTML 属性的属性
document.getElementById('box').id; //获取 iddocument.getElementById('box').id = 'person'; //设置 iddocument.getElementById('box').title; //获取 titledocument.getElementById('box').title = '标题' //设置 titledocument.getElementById('box').style; //获取 CSSStyleDeclaration 对象document.getElementById('box').style.color; //获取 style 对象中 color 的值document.getElementById('box').style.color = 'red'; //设置 style 对象中 color 的值document.getElementById('box').className; //获取 classdocument.getElementById('box').className = 'box'; //设置 classalert(document.getElementById('box').bbb); //获取自定义属性的值,非 IE 不支持
层次节点属性(遍历节点树属性)
节点的层次结构可以划分为:父节点与子节点、兄弟节点这两种。当我们获取其中一个元素节点的时候,就可以使用层次节点属性来获取它相关层次的节点。
层次节点属性
childNodes属性
childeNodes 属性可以获取某一个元素节点的所有子节点,这些子节点包含元素子节点和文本子节点。
var box = document.getElementById('box'); //获取一个元素节点alert(box.childNodes.length); //获取这个元素节点的所有子节点alert(box.childNodes[0]); //获取第一个子节点对象
PS:使用 childNodes[n]返回子节点对象的时候,有可能返回的是元素子节点,比如HTMLElement;也有可能返回的是文本子节点,比如 Text。元素子节点可以使用 nodeName或者 tagName 获取标签名称,而文本子节点可以使用 nodeValue 获取。
for (var i = 0; i < box.childNodes.length; i ++) { //判断是元素节点,输出元素标签名 if (box.childNodes[i].nodeType === 1) { alert('元素节点:' + box.childNodes[i].nodeName); //判断是文本节点,输出文本内容 } else if (box.childNodes[i].nodeType === 3) { alert('文本节点:' + box.childNodes[i].nodeValue); }}
PS:在获取到文本节点的时候,是无法使用 innerHTML 这个属性输出文本内容的。这个非标准的属性必须在获取元素节点的时候,才能输出里面包含的文本。
alert(box.innerHTML); //innerHTML 和 nodeValue 第一个区别
PS:innerHTML 和 nodeValue 第一个区别,就是取值的。那么第二个区别就是赋值的时候, nodeValue 会把包含在文本里的 HTML 转义成特殊字符, 从而达到形成单纯文本的效果。
box.childNodes[0].nodeValue = '<strong>abc</strong>';//结果为:<strong>abc</strong>box.innerHTML = '<strong>abc</strong>'; //结果为: abc
firstChild 和 lastChild 属性
firstChild 用于获取当前元素节点的第一个子节点,相当于 childNodes[0]
lastChild 用于获取当前元素节点的最后一个子节点,相当于
childNodes[box.childNodes.length - 1]。
ownerDocument 属性
ownerDocument 属性返回该节点的文档对象根节点,返回的对象相当于 document。
alert(box.ownerDocument === document); //true,根节点
parentNode属性
parentNode 属性返回该节点的父节点
alert(box.parentNode.nodeName); //获取父节点的标签名
previousSibling、nextSibling
previousSibling 属性返回该节点的前一个同级节点,nextSibling 属性返回该节点的后一个同级节点。
alert(box.lastChild.previousSibling); //获取前一个同级节点alert(box.firstChild.nextSibling); //获取后一个同级节点
attributes 属性
attributes 属性返回该节点的属性节点集合。
document.getElementById('box').attributes //NamedNodeMapdocument.getElementById('box').attributes.length;//返回属性节点个数document.getElementById('box').attributes[0]; //Attr,返回最后一个属性节点document.getElementById('box').attributes[0].nodeType; //2,节点类型document.getElementById('box').attributes[0].nodeValue; //属性值document.getElementById('box').attributes['id']; //Attr,返回属性为 id 的节点document.getElementById('box').attributes.getNamedItem('id'); //Attr
忽略空白文本节点
var body = document.getElementsByTagName('body')[0];//获取 body 元素节点alert(body.childNodes.length); //得到子节点个数,IE3 个,非 IE7 个
PS:在非 IE 中,标准的 DOM 具有识别空白文本节点的功能,所以在火狐浏览器是 7个,而 IE 自动忽略了,如果要保持一致的子元素节点,需要手工忽略掉它。
function filterSpaceNode(nodes) {//过滤(忽略空白节点) var ret = []; //新数组 for (var i = 0; i < nodes.length; i ++) { //如果识别到空白文本节点,就不添加数组 if (nodes[i].nodeType == 3 && /^\s+$/.test(nodes[i].nodeValue)){ continue; } //把每次的元素节点,添加到数组里 ret.push(nodes[i]); } return ret;}
PS:上面的方法,采用的忽略空白文件节点的方法,把得到元素节点累加到数组里返回。那么还有一种做法是,直接删除空位文件节点即可。
function filterSpaceNode(nodes) { for (var i = 0; i < nodes.length; i ++) {//过滤(忽略空白节点) if (nodes[i].nodeType == 3 && /^\s+$/.test(nodes[i].nodeValue)) { //得到空白节点之后,移到父节点上,删除子节点 nodes[i].parentNode.removeChild(nodes[i]); } } return nodes;}
PS:如果 firstChild、lastChild、previousSibling 和 nextSibling 在获取节点的过程中遇到空白节点,我们该怎么处理掉呢?
function removeWhiteNode(nodes) { for (var i = 0; i < nodes.childNodes.length; i ++) { if (nodes.childNodes[i].nodeType === 3 && /^\s+$/.test(nodes.childNodes[i].nodeValue)){ nodes.childNodes[i].parentNode. removeChild(nodes.childNodes[i]); } } return nodes;}
第4章 节点操作(DOM中的常见方法)
DOM 不单单可以查找节点,也可以创建节点、复制节点、插入节点、删除节点和替换节点。
节点操作方法
write()
write()方法可以把任意字符串插入到文档中去。
document.write('<p>这是一个段落!</p>')'; //输出任意字符串
createElement()
createElement()方法可以创建一个元素节点。
document.createElement('p'); //创建一个元素节点
appendChild()
appendChild()方法将一个新节点添加到某个节点的子节点列表的末尾上。
var box = document.getElementById('box'); //获取某一个元素节点var p = document.createElement('p'); //创建一个新元素节点<p>box.appendChild(p); //把新元素节点<p>添加子节点末尾
createTextNode()
createTextNode()方法创建一个文本节点。
var text = document.createTextNode('段落'); //创建一个文本节点p.appendChild(text); //将文本节点添加到子节点末尾
insertBefore()
insertBefore()方法可以把节点创建到指定节点的前面。
box.parentNode.insertBefore(p, box); //把<div>之前创建一个节点
PS:insertBefore()方法可以给当前元素的前面创建一个节点,但却没有提供给当前元素的后面创建一个节点。那么,我们可以用已有的知识创建一个 insertAfter()函数。
function insertAfter(newElement, targetElement) { //得到父节点 var parent = targetElement.parentNode; //如果最后一个子节点是当前元素,那么直接添加即可 if (parent.lastChild === targetElement) { parent.appendChild(newElement); } else { //否则,在当前节点的下一个节点之前添加 parent.insertBefore(newElement, targetElement.nextSibling); }}
PS:createElement 在创建一般元素节点的时候,浏览器的兼容性都还比较好。但在几个特殊标签上,比如 iframe、input 中的 radio 和 checkbox、button 元素中,可能会在 IE6,7以下的浏览器存在一些不兼容。
var input = null;if (BrowserDetect.browser == 'Internet Explorer' && BrowserDetect.version <= 7) { //判断 IE6,7,使用字符串的方式 input = document.createElement("<input type=\"radio\" name=\"sex\">");} else { //标准浏览器,使用标准方式 input = document.createElement('input'); input.setAttribute('type', 'radio'); input.setAttribute('name', 'sex');}document.getElementsByTagName('body')[0].appendChild(input);
repalceChild()
replaceChild()方法可以把节点替换成指定的节点。
box.parentNode.replaceChild(p,box); //把<div>换成了<p>
cloneNode()
cloneNode()方法可以把子节点复制出来。
var box = document.getElementById('box');var clone = box.firstChild.cloneNode(true); //获取第一个子节点,true 表示复制内容box.appendChild(clone); //添加到子节点列表末尾
removeChild()
removeChild()方法可以把一个节点移出掉
box.parentNode.removeChild(box); //删除指定节点
第5章DOM类型
DOM 自身存在很多类型,在 前几章中大部分都有所接触
比如 Element 类型 :表示的是元素节点,比如 Text 类型:表示的是文本节点。
DOM 也提供了一些扩展功能。DOM 前几章中,我们了解了 DOM 的节点并且了解怎样查询和操作节点,而本身这些不同的节点,又有着不同的类型。
DOM 类型
Node 类型
Node 接口是 DOM1 级就定义了,Node 接口定义了 12 个数值常量以表示每个节点的类型值。除了 IE 之外,所有浏览器都可以访问这个类型。
Node 的常量
虽然这里介绍了 12 种节点对象的属性,用的多的其实也就几个而已。
alert(Node.ELEMENT_NODE); //1,元素节点类型值alert(Node.TEXT_NODE); //2,文本节点类型值
PS:我们建议使用 Node 类型的属性来代替 1,2 这些阿拉伯数字,有可能大家会觉得这样岂不是很繁琐吗?并且还有一个问题就是 IE 不支持 Node 类型。
如果只有两个属性的话,用 1,2 来代替会特别方便,但如果属性特别多的情况下,1 、2、3、4、5、6、7、8、9、10、11、12,你根本就分不清哪个数字代表的是哪个节点。当然 ,如果你只用 1,2 两个节点,那就另当别论了。
IE 不支持,我们可以模拟一个类,让 IE 也支持
if (typeof Node == 'undefined') { //IE 返回true window.Node = { ELEMENT_NODE : 1, TEXT_NODE : 3 };}
Document 类型
Document 类型表示文档,或文档的根节点,而这个节点是隐藏的,没有具体的元素标签。
document; //documentdocument.nodeType; //9,类型值document.childNodes[0]; //DocumentType,第一个子节点对象document.childNodes[0].nodeType; //非 IE 为 10,IE 为 8document.childNodes[1]; //HTMLHtmlElementdocument.childNodes[1].nodeName; //HTML
如果想直接得到<html>
标签的元素节点对象 HTMLHtmlElement,不必使用 childNodes属性这么麻烦,可以使用 documentElement 即可。
document.documentElement; //HTMLHtmlElement
在很多情况下, 我们并不需要得到<html>
标签的元素节点, 而需要得到更常用的<body>
标签,之前我们采用的是:document.getElementsByTagName(‘body’)[0],那么这里提供一个更加简便的方法:document.body。
document.body; //HTMLBodyElement
在<html>
之前还有一个文档声明:会作为某些浏览器的第一个节点来处理,这里提供了一个简便方法来处理:document.doctype。
document.doctype; //DocumentType
PS:IE8 中,如果使用子节点访问,IE8 之前会解释为注释类型 Comment 节点,而document.doctype 则会返回 null。
document.childNodes[0].nodeName //IE 会是#Comment
在 Document 中有一些遗留的属性和对象合集,可以快速的帮助我们精确的处理一些任务。
//属性document.title; //获取和设置<title>标签的值document.URL; //获取 URL 路径document.domain; //获取域名,服务器端document.referrer; //获取上一个 URL,服务器端//对象集合document.anchors; //获取文档中带name属性的<a>元素集合document.links; //获取文档中带 href 属性的<a>元素集合document.applets; //获取文档中<applet>元素集合,已不用document.forms; //获取文档中<form>元素集合document.images; //获取文档中<img>元素集合
Element 类型
Element 类型用于表现 HTML 中的元素节点。在 前面几章,我们已经可以对元素节点进行查找、创建等操作,元素节点的 nodeType 为 1,nodeName 为元素的标签名。
元素节点对象在非 IE 浏览器可以返回它具体元素节点的对象类型。
元素对应类型表
PS:以上给出了部分对应,更多的元素对应类型,直接访问调用即可。
Text 类型
Text 类型用于表现文本节点类型,文本不包含 HTML,或包含转义后的HTML。文本节点的 nodeType 为 3。
//在同时创建两个同一级别的文本节点的时候,会产生分离的两个节点。var box = document.createElement('div');var text = document.createTextNode('Mr.');var text2 = document.createTextNode(Lee!);box.appendChild(text);box.appendChild(text2);document.body.appendChild(box);alert(box.childNodes.length); //2,两个文本节点
PS:把两个同邻的文本节点合并在一起使用 normalize()即可。
box.normalize(); //合并成一个节点
PS:有合并就有分离,通过 splitText(num)即可实现节点分离。
box.firstChild.splitText(3); //分离一个节点
除了上面的两种方法外,Text 还提供了一些别的 DOM 操作的方法如下:
var box = document.getElementById('box');box.firstChild.deleteData(0,2); //删除从 0 位置的 2 个字符box.firstChild.insertData(0,'Hello.'); //从 0 位置添加指定字符box.firstChild.replaceData(0,2,'Miss'); //从 0 位置替换掉 2 个指定字符box.firstChild.substringData(0,2); //从 0 位置获取 2 个字符,直接输出alert(box.firstChild.nodeValue); //输出结果
Comment 类型
Comment 类型表示文档中的注释。nodeType 是 8,nodeName 是#comment,nodeValue是注释的内容。
var box = document.getElementById('box');alert(box.firstChild); //Comment
PS:在 IE 中,注释节点可以使用!当作元素来访问。
var comment = document.getElementsByTagName('!');alert(comment.length);
5.6Attr类型
Attr 类型表示文档元素中的属性。nodeType 为 11,nodeName 为属性名,nodeValue 为属性值。DOM 基础篇已经详细介绍过,略。
第6章 DOM扩展知识
呈现模式
从 IE6 开始开始区分标准模式和混杂模式(怪异模式),主要是看文档的声明。IE 为document 对象添加了一个名为 compatMode 属性,这个属性可以识别 IE 浏览器的文档处于什么模式如果是标准模式,则返回 CSS1Compat,如果是混杂模式则返BackCompat。
if (document.compatMode == 'CSS1Compat') { alert(document.documentElement.clientWidth);} else { alert(document.body.clientWidth);}
PS: 后来 Firefox、 Opera 和 Chrome 都实现了这个属性。 从 IE8 后, 又引入 documentMode新属性,因为 IE8 有 3 种呈现模式分别为标准模式 8,仿真模式 7,混杂模式 5。所以如果想测试 IE8 的标准模式,就判断 document.documentMode > 7 即可。
滚动
DOM 提供了一些滚动页面的方法,如下:
document.getElementById('box').scrollIntoView(); //设置指定可见
children属性
由于子节点空白问题,IE 和其他浏览器解释不一致。虽然可以过滤掉,但如果只是想得到有效子节点,可以使用 children 属性,支持的浏览器为:IE5+、Firefox3.5+、Safari2+ 、Opera8+和 Chrome,这个属性是非标准的。
var box = document.getElementById('box');alert(box.children.length); //得到有效子节点数目
contains()方法
判断一个节点是不是另一个节点的后代,我们可以使用 contains()方法。这个方法是 IE率先使用的,开发人员无须遍历即可获取此信息。
var box = document.getElementById('box');alert(box.contains(box.firstChild)); //true
PS:早期的 Firefox 不支持这个方法,新版的支持了,其他浏览器也都支持,Safari2.x浏览器支持的有问题,无法使用。所以,必须做兼容。在 Firefox 的 DOM3 级实现中提供了一个替代的方法 compareDocumentPosition()方法。
这个方法确定两个节点之间的关系。
var box = document.getElementById('box');alert(box.compareDocumentPosition(box.firstChild)); //20
关系掩码表
PS:为什么会出现 20,那是因为满足了 4 和 16 两项,最后相加了。为了能让所有浏览器都可以兼容,我们必须写一个兼容性的函数。
//传递参考节点(父节点),和其他节点(子节点)function contains(refNode, otherNode) { //判断支持 contains,并且非 Safari 浏览器 if (typeof refNode.contains != 'undefined' && !(BrowserDetect.browser == 'Safari' && BrowserDetect.version < 3)) { return refNode.contains(otherNode); //判断支持 compareDocumentPosition 的浏览器,大于 16 就是包含 } else if (typeof refNode.compareDocumentPosition == 'function') { return !!(refNode.compareDocumentPosition(otherNode) > 16); } else { //更低的浏览器兼容,通过递归一个个获取他的父节点是否存在 var node = otherNode.parentNode; do { if (node === refNode) { return true; } else { node = node.parentNode; } } while (node != null); } return false;}
第7章 DOM操作内容
虽然在之前我们已经学习了各种 DOM 操作的方法,这里所介绍是 innerText、innerHTML、outerText 和 outerHTML 等属性。除了之前用过的 innerHTML 之外,其他三个还么有涉及到。
innerText 属性
document.getElementById('box').innerText; //获取文本内容(如有 html 直接过滤掉)document.getElementById('box').innerText = 'Mr.Lee'; //设置文本(如有 html 转义)
PS:除了 Firefox 之外,其他浏览器均支持这个方法。但 Firefox 的 DOM3 级提供了另外一个类似的属性:textContent,做上兼容即可通用。
document.getElementById('box').textContent; //Firefox 支持//兼容方案function getInnerText(element) { return (typeof element.textContent == 'string') ? element.textContent : element.innerText;}function setInnerText(element, text) { if (typeof element.textContent == 'string') { element.textContent = text; } else { element.innerText = text; }}
innerHTML 属性
这个属性之前就已经研究过,不拒绝 HTML。
document.getElementById('box').innerHTML; //获取文本(不过滤 HTML)document.getElementById('box').innerHTML = '<b>123</b>'; //可解析 HTML
虽然 innerHTML 可以插入 HTML,但本身还是有一定的限制,也就是所谓的作用域元
素,离开这个作用域就无效了。
box.innerHTML = "<script>alert('Lee');</script>"; //<script>元素不能被执行box.innerHTML = "<style>background:red;</style>"; //<style>元素不能被执行
outerText
outerText 在取值的时候和 innerText 一样,同时火狐不支持,而赋值方法相当危险,他不单替换了文本内容,还将元素直接抹去。
var box = document.getElementById('box');box.outerText = '<b>123</b>';alert(document.getElementById('box')); //null,建议不去使用
outerHTML
outerHTML 属性在取值和 innerHTML 一致,但和 outerText 也一样,很危险,赋值的之后会将元素抹去。
var box = document.getElementById('box');box.outerHTML = '123';alert(document.getElementById('box')); //null,建议不去使用,火狐旧版未抹去
PS:关于最常用的 innerHTML 属性和节点操作方法的比较,在插入大量 HTML 标记时使用 innerHTML 的效率明显要高很多。因为在设置 innerHTML 时,会创建一个 HTML 解析器。这个解析器是浏览器级别的(C++编写),因此执行 JavaScript 会快的多。但,创建和销毁 HTML 解析器也会带来性能损失。最好控制在最合理的范围内,如下:
for (var i = 0; i < 10; i ++) { ul.innerHTML = '<li>item</li>'; //避免频繁}//改for (var i = 0; i < 10; i ++) { a = '<li>item</li>'; //临时保存}ul.innerHTML = a;
第8章 DOM操作表格
DOM 在操作生成 HTML 上, 还是比较简明的。 不过, 由于浏览器总是存在兼容和陷阱 ,导致最终的操作就不是那么简单方便了。 本章主要了解一下 DOM操作表格和样式的一些知识。
<table>
标签是 HTML 中结构最为复杂的一个,我们可以通过 DOM 来创建生成它,或者 HTML DOM 来操作它。
PS:HTML DOM 提供了更加方便快捷的方式来操作Table, 有手册
//需要操作的 table
//使用 DOM 来创建这个表格var table = document.createElement('table');table.border = 1;table.width = 300;var caption = document.createElement('caption');table.appendChild(caption);caption.appendChild(document.createTextNode('人员表'));var thead = document.createElement('thead');table.appendChild(thead);var tr = document.createElement('tr');thead.appendChild(tr);var th1 = document.createElement('th');var th2 = document.createElement('th');var th3 = document.createElement('th');tr.appendChild(th1);th1.appendChild(document.createTextNode('姓名'));tr.appendChild(th2);th2.appendChild(document.createTextNode('年龄'));document.body.appendChild(table);
PS:使用 DOM 来创建表格其实已经没有什么难度,就是有点儿小烦而已。下面我们再使用 HTML DOM 来获取和创建这个相同的表格。HTML DOM 中,给这些元素标签提供了一些属性和方法
< tbody>元素添加的属性和方法
< tr>元素添加的属性和方法
PS:因为表格较为繁杂,层次也多,在使用之前所学习的 DOM 只是来获取某个元素会非常难受,所以使用 HTML DOM 会清晰很多
//使用 HTML DOM 来获取表格元素var table = document.getElementsByTagName('table')[0]; //获取 table 引用//按照之前的 DOM 节点方法获取<caption>alert(table.children[0].innerHTML); //获取 caption 的内容
PS:这里使用了 children[0]本身就忽略了空白,如果使用 firstChild 或者 childNodes[0]需要更多的代码。
//按 HTML DOM 来获取表格的<caption>alert(table.caption.innerHTML); //获取 caption 的内容
//按 HTML DOM 来获取表头表尾<thead>、<tfoot>alert(table.tHead); //获取表头alert(table.tFoot); //获取表尾
//按 HTML DOM 来获取表体<tbody>alert(table.tBodies); //获取表体的集合
PS:在一个表格中和是唯一的,只能有一个。而不是唯一的可以有多个,这样导致最后返回的和是元素引用,而返回的是元素集合。
//按 HTML DOM 来获取表格的行数alert(table.rows.length); //获取行数的集合,数量//按 HTML DOM 来获取表格主体里的行数alert(table.tBodies[0].rows.length); //获取主体的行数的集合,数量//按 HTML DOM 来获取表格主体内第一行的单元格数量(tr)alert(table.tBodies[0].rows[0].cells.length); //获取第一行单元格的数量//按 HTML DOM 来获取表格主体内第一行第一个单元格的内容(td)alert(table.tBodies[0].rows[0].cells[0].innerHTML); //获取第一行第一个单元格的内容//按 HTML DOM 来删除标题、表头、表尾、行、单元格table.deleteCaption(); //删除标题table.deleteTHead(); //删除<thead>table.tBodies[0].deleteRow(0); //删除<tr>一行table.tBodies[0].rows[0].deleteCell(0); //删除<td>一个单元格//按 HTML DOM 创建一个表格var table = document.createElement('table');table.border = 1;table.width = 300;table.createCaption().innerHTML = '人员表';//table.createTHead();//table.tHead.insertRow(0);var thead = table.createTHead();var tr = thead.insertRow(0);var td = tr.insertCell(0);td.appendChild(document.createTextNode('数据'));var td2 = tr.insertCell(1);td2.appendChild(document.createTextNode('数据 2'));document.body.appendChild(table);
PS:在创建表格的时候<table>
、<tbody>
、<th>
没有特定的方法,需要使用 document来创建。也可以模拟已有的方法编写特定的函数即可,例如:insertTH()之类的。
第9章 DOM操作样式
CSS 作为(X)HTML 的辅助,可以增强页面的显示效果。但不是每个浏览器都能支持最新的 CSS 能力。CSS 的能力和 DOM 级别密切相关,所以我们有必要检测当前浏览器支持CSS 能力的级别。
DOM1 级实现了最基本的文档处理,DOM2 和 DOM3 在这个基础上增加了更多的交互能力,这里我们主要探讨 CSS,DOM2 增加了 CSS 编程访问方式和改变 CSS 样式信息。
DOM 一致性检测
//检测浏览器是否支持 DOM1 级 CSS 能力或 DOM2 级 CSS 能力alert('DOM1 级 CSS 能力:' + document.implementation.hasFeature('CSS', '2.0'));alert('DOM2 级 CSS 能力:' + document.implementation.hasFeature('CSS2', '2.0'));
PS:这种检测方案在 IE 浏览器上不精确,IE6 中,hasFeature()方法只为 HTML 和版本1.0 返回 true,其他所有功能均返回 false。但 IE 浏览器还是支持最常用的 CSS2 模块。
访问元素的样式
任何 HTML 元素标签都会有一个通用的属性:style。它会返回CSSStypeDeclaration 对象。下面我们看几个最常见的行内 style 样式的访问方式。
CSS 属性及 JavaScript 调用
var box = document.getElementById('box'); //获取 boxbox.style.cssFloat.style; //CSSStyleDeclarationbox.style.cssFloat.style.color; //redbox.style.cssFloat.style.fontSize; //20pxbox.style.cssFloat || box.style.styleFloat; //left,非 IE 用 cssFloat,IE 用 styleFloat
PS:以上取值方式也可以赋值,最后一种赋值可以如下:
typeof box.style.cssFloat != 'undefined' ?box.style.cssFloat = 'right' : box.style.styleFloat = 'right';
DOM2 级样式规范为 style 定义了一些属性和方法
box.style.cssText; //获取 CSS 代码//box.style.length; //3,IE 不支持//box.style.removeProperty('color'); //移除某个 CSS 属性,IE 不支持//box.style.setProperty('color','blue'); //设置某个 CSS 属性,IE 不支持
PS:Firefox、Safari、Opera9+、Chrome 支持这些属性和方法。IE 只支持 cssText,而getPropertyCSSValue()方法只有 Safari3+和 Chrome 支持。
PS:style 属性仅仅只能获取行内的 CSS 样式,对于另外两种形式内联<style>
和链接<link>
方式则无法获取到。
虽然可以通过 style 来获取单一值的 CSS 样式,但对于复合值的样式信息,就需要通过计算样式来获取。DOM2 级样式,window 对象下提供了getComputedStyle()方法。接受两个参数,需要计算的样式元素,第二个伪类(:hover),如果没有没有伪类,就填 null。
PS:IE 不支持这个 DOM2 级的方法,但有个类似的属性可以使用 currentStyle 属性。
var box = document.getElementById('box');var style = window.getComputedStyle ?window.getComputedStyle(box, null) : null || box.currentStyle;alert(style .color); //颜色在不同的浏览器会有 rgb()格式alert(style .border); //不同浏览器不同的结果alert(style .fontFamily); //计算显示复合的样式值alert(box.style.fontFamily); //空
PS: border 属性是一个综合属性, 所以他在 Chrome 显示了, Firefox 为空, IE 为 undefined 。
所谓综合性属性,就是 XHTML 课程里所的简写形式,所以,DOM 在获取 CSS 的时候, 最好采用完整写法兼容性最好,比如:border-top-color 之类的。
操作样式表
使用 style 属性可以设置行内的 CSS 样式,而通过 id 和 class 调用是最常用的方法。
box.id = 'pox'; //把 ID 改变会带来灾难性的问题box.className = 'red'; //通过 className 关键字来设置样式
在添加 className 的时候,我们想给一个元素添加多个 class 是没有办法的,后面一个必将覆盖掉前面一个,所以必须来写个函数:
//判断是否存在这个 classfunction hasClass(element, className) { return element.className.match(new RegExp('(\\s|^)'+className+'(\\s|$)'));}//添加一个 class,如果不存在的话function addClass(element, className) { if (!hasClass(element, className)) { element.className += " "+className; }}//删除一个 class,如果存在的话function removeClass(element, className) { if (hasClass(element, className)) { element.className = element.className.replace( new RegExp('(\\s|^)'+className+'(\\s|$)'),' '); }}
之前我们使用 style 属性,仅仅只能获取和设置行内的样式,如果是通过内联<style>
或链接<link>
提供的样式规则就无可奈何了,然后我们又学习了 getComputedStyle() 和currentStyle,这只能获取却无法设置。
CSSStyleSheet 类型表示通过<link>
元素和<style>
元素包含的样式表。
document.implementation.hasFeature('StyleSheets', '2.0') //是否支持 DOM2 级样式表document.getElementsByTagName('link')[0]; //HTMLLinkElementdocument.getElementsByTagName('style')[0]; //HTMLStyleElement
这两个元素本身返回的是 HTMLLinkElement 和 HTMLStyleElement 类型,但
CSSStyleSheet 类型更加通用一些。得到这个类型非 IE 使用 sheet 属性,IE 使用 styleSheet;
var link = document.getElementsByTagName('link')[0];var sheet = link.sheet || link.styleSheet; //得到 CSSStyleSheet
sheet.disabled; //false,可设置为 truesheet.href; //css 的 URLsheet.media; //MediaList,集合sheet.media[0]; //第一个 media 的值sheet.title; //得到 title 属性的值sheet.cssRules //CSSRuleList,样式表规则集合sheet.deleteRule(0); //删除第一个样式规则sheet.insertRule("body {background-color:red}", 0); //在第一个位置添加一个样式规则
PS:除了几个不用和 IE 不支持的我们忽略了,还有三个有 IE 对应的另一种方式:
sheet.rules; //代替 cssRules 的 IE 版本sheet.removeRule(0); //代替 deleteRule 的 IE 版本sheet.addRule("body", "background-color:red", 0);//代替 insertRule 的 IE 版本
除了刚才的方法可以得到 CSSStyleSheet 类型,还有一种方法是通过 document 的styleSheets 属性来获取。
document.styleSheets; //StyleSheetList,集合var sheet = document.styleSheets[0]; //CSSStyleSheet,第一个样式表对象
为了添加 CSS 规则,并且兼容所有浏览器,我们必须写一个函数:
var sheet = document.styleSheets[0];insertRule(sheet, "body", "background-color:red;", 0);function insertRule(sheet, selectorText, cssText, position) { //如果是非 IE if (sheet.insertRule) { sheet.insertRule(selectorText + "{" + cssText + "}", position); //如果是 IE } else if (sheet.addRule) { sheet.addRule(selectorText, cssText, position); }}
为了删除 CSS 规则,并且兼容所有浏览器,我们必须写一个函数:var sheet = document.styleSheets[0];deleteRule(sheet, 0);function deleteRule(sheet, index) { //如果是非 IE if (sheet.deleteRule) { sheet.deleteRule(index); //如果是 IE } else if (sheet.removeRule) { sheet.removeRule(index); }}
通过 CSSRules 属性(非 IE)和 rules 属性(IE),我们可以获得样式表的规则集合列表。这
样我们就可以对每个样式进行具体的操作了。
var sheet = document.styleSheets[0]; //CSSStyleSheetvar rules = sheet.cssRules || sheet.rules; //CSSRuleList,样式表的规则集合列表var rule = rules[0]; //CSSStyleRule,样式表第一个规则
CSSStyleRule 可以使用的属性
rule.cssText; //当前规则的样式文本rule.selectorText; //#box,样式的选择符rule.style.color; //red,得到具体样式值
PS:Chrome 浏览器在本地运行时会出现问题,rules 会变成 null,只要把它放到服务器上允许即可正常。
总结:三种操作 CSS 的方法
第10章 DOM元素尺寸和位置
获取元素CSS大小
通过 style内联获取元素的大小
var box = document.getElementById('box'); //获取元素box.style.width; //200px、空box.style.height; //200px、空
PS:style 获取只能获取到行内 style 属性的 CSS 样式中的宽和高,如果有获取;如果没有则返回空。
通过计算获取元素的大小
var style = window.getComputedStyle ?window.getComputedStyle(box, null) : null || box.currentStyle;style.width; //1424px、200px、autostyle.height; //18px、200px、auto
PS:通过计算获取元素的大小,无关你是否是行内、内联或者链接,它经过计算后得到的结果返回出来。如果本身设置大小,它会返回元素的大小,如果本身没有设置,非 IE浏览器会返回默认的大小,IE 浏览器返回 auto。
通过 CSSStyleSheet 对象中的cssRules(或 rules)属性获取元素大小
var sheet = document.styleSheets[0]; //获取 link 或 stylevar rule = (sheet.cssRules || sheet.rules)[0]; //获取第一条规则rule.style.width; //200px、空rule.style.height; //200px、空
PS:cssRules(或 rules)只能获取到内联和链接样式的宽和高,不能获取到行内和计算后的样式
总结:以上的三种 CSS 获取元素大小的方法,只能获取元素的 CSS 大小,却无法获取元素本身实际的大小。比如加上了内边距、滚动条、边框之类的
获取元素实际大小
clientWidth 和 clientHeight
这组属性可以获取元素可视区的大小,可以得到元素内容及内边距所占据的空间大小。
PS: 返回了元素大小, 但没有单位, 默认单位是 px, 如果你强行设置了单位, 比如 100em之类,它还是会返回 px 的大小。(CSS 获取的话,是照着你设置的样式获取)。
PS:对于元素的实际大小,clientWidth 和 clientHeight 理解方式如下:
- 增加边框,无变化,为 200;
- 增加外边距,无变化,为 200;
- 增加滚动条,最终值等于原本大小减去滚动条的大小,为 184;
- 增加内边距,最终值等于原本大小加上内边距的大小,为 220;
PS:如果说没有设置任何 CSS 的宽和高度,那么非 IE 浏览器会算上滚动条和内边距的计算后的大小,而 IE 浏览器则返回 0。
scrollWidth 和 scrollHeight
这组属性可以获取滚动内容的元素大小
PS:返回了元素大小,默认单位是 px。如果没有设置任何 CSS 的宽和高度,它会得到计算后的宽度和高度。
PS:对于元素的实际大小,scrollWidth 和 scrollHeight 理解如下:
- 增加边框,不同浏览器有不同解释:
a) Firefox 和 Opera 浏览器会增加边框的大小,220 x 220
b) IE、Chrome 和 Safari 浏览器会忽略边框大小,200 x 200
c) IE 浏览器只显示它本来内容的高度,200 x 18 - 增加内边距,最终值会等于原本大小加上内边距大小,220 x 220,IE 为 220 x 38
- 增加滚动条,最终值会等于原本大小减去滚动条大小,184 x 184,IE 为 184 x 18
- 增加外边据,无变化。
- 增加内容溢出,Firefox、Chrome 和 IE 获取实际内容高度,Opera 比前三个浏览器获取的高度偏小,Safari 比前三个浏览器获取的高度偏大。
- IE浏览器在指定的高度下获取scrollHeight会理解为获取有效内容的高度
- scrollWidth和scrollHeight会随着浏览器窗口大小的变化而变化
offsetWidth 和 offsetHeight
这组属性可以返回元素实际大小,包含边框、内边距和滚动条。
PS:返回了元素大小,默认单位是 px。如果没有设置任何 CSS 的宽和高度,他会得到计算后的宽度和高度。
PS:对于元素的实际大小,offsetWidth 和 offsetHeight 理解如下:
- 增加边框,最终值会等于原本大小加上边框大小,为 220;
- 增加内边距,最终值会等于原本大小加上内边距大小,为 220;
- 增加外边据,无变化;
- 增加滚动条,无变化,不会减小;
PS:对于元素大小的获取,一般是块级(block)元素并且以设置了 CSS 大小的元素较为方便。如果是内联元素(inline)或者没有设置大小的元素就尤为麻烦,所以,建议使用的时候注意。
获取元素周边大小
clientLeft 和 clientTop
这组属性可以获取元素设置了左边框和上边框的大小。
PS:目前只提供了 Left 和 Top 这组,并没有提供 Right 和 Bottom。如果四条边宽度不
同的话,可以直接通过计算后的样式获取,或者采用以上三组获取元素大小的减法求得。
offsetLeft 和 offsetTop
这组属性可以获取当前元素相对于父元素的位置。
PS:获取元素当前相对于父元素的位置,最好将它设置为定位 position:absolute;否则不同的浏览器会有不同的解释。
**PS:加上边框和内边距不会影响它的位置,但加上外边据会累加。
box.offsetParent; //得到父元素**
PS:offsetParent 中,如果本身父元素是,非 IE 返回 body 对象,IE 返回 html 对象。如果两个元素嵌套,如果上父元素没有使用定位 position:absolute,那么 offsetParent 将返回 body 对象或 html 对象。所以,在获取 offsetLeft 和 offsetTop 时候,CSS 定位很重要。
如果说,在很多层次里,外层已经定位,我们怎么获取里层的元素距离 body 或 html元素之间的距离呢?也就是获取任意一个元素距离页面上的位置。那么我们可以编写函数 ,通过不停的向上回溯获取累加来实现。
box.offsetTop + box.offsetParent.offsetTop; //只有两层的情况下如果多层的话,就必须使用循环或递归。function offsetLeft(element) {var left = element.offsetLeft; //得到第一层距离var parent = element.offsetParent; //得到第一个父元素while (parent !== null) { //如果还有上一层父元素left += parent.offsetLeft; //把本层的距离累加parent = parent.offsetParent; //得到本层的父元素} //然后继续循环return left;}
scrollTop 和 scrollLeft
这组属性可以获取滚动条被隐藏的区域大小,也可设置定位到该区域。
如果要让滚动条滚动到最初始的位置,那么可以写一个函数:
function scrollStart(element) { if (element.scrollTop != 0) element.scrollTop = 0;}
获取元素位置getBoundingClientRect()
上一节已经通过几组属性可以获取元素所需的位置,那么这节课补充一个 DOM 的方法:getBoundingClientRect()。这个方法返回一个矩形对象,包含四个属性:left、top、right和 bottom。分别表示元素各边与页面上边和左边的距离。
var box = document.getElementById('box'); //获取元素alert(box.getBoundingClientRect().top); //元素上边距离页面上边的距离alert(box.getBoundingClientRect().right); //元素右边距离页面左边的距离alert(box.getBoundingClientRect().bottom); //元素下边距离页面上边的距离alert(box.getBoundingClientRect().left); //元素左边距离页面左边的距离
PS:IE、Firefox3+、Opera9.5、Chrome、Safari 支持,在 IE 中,默认坐标从(2,2)开始计算,导致最终距离比其他浏览器多出两个像素,我们需要做个兼容。
document.documentElement.clientTop; //非 IE 为 0,IE 为 2document.documentElement.clientLeft; //非 IE 为 0,IE 为 2function getRect(element) { var rect = element.getBoundingClientRect(); var top = document.documentElement.clientTop; var left = document.documentElement.clientLeft; return { top : rect.top - top, bottom : rect.bottom - top, left : rect.left - left, right : rect.right - left }}
PS:分别加上外边据、内边距、边框和滚动条,用于测试所有浏览器是否一致。
第11章 动态加载脚本和样式
动态脚本
当网站需求变大,脚本的需求也逐步变大。我们就不得不引入太多的 JS 脚本而降低了整站的性能,所以就出现了动态脚本的概念,在适时的时候加载相应的脚本。
比如:我们想在需要检测浏览器的时候,再引入检测文件。
var flag = true; //设置 true 再加载if (flag) { loadScript('browserdetect.js'); //设置加载的 js}function loadScript(url) { var script = document.createElement('script'); script.type = 'text/javascript'; script.src = url; //document.head.appendChild(script); //document.head 表示<head> document.getElementsByTagName('head')[0].appendChild(script);}
PS:document.head 调用,IE 不支持,会报错!
//动态执行 jsvar script = document.createElement('script');script.type = 'text/javascript';var text = document.createTextNode("alert('Lee')"); //IE 浏览器报错script.appendChild(text);document.getElementsByTagName('head')[0].appendChild(script);
**PS:IE 浏览器认为 script 是特殊元素,不能在访问子节点。为了兼容,可以使用 text属性来代替。
script.text = “alert(”)”; //IE 可以支持了。**
PS:当然,如果不支持 text,那么就可以针对不同的浏览器特性来使用不同的方法。 这里就忽略写法了。
动态样式
为了动态的加载样式表, 比如切换网站皮肤。 样式表有两种方式进行加载, 一种是< link>标签,一种是< style>标签。
//动态执行 linkvar flag = true;if (flag) { loadStyles('basic.css');}function loadStyles(url) { var link = document.createElement('link'); link.rel = 'stylesheet'; link.type = 'text/css'; link.href = url; document.getElementsByTagName('head')[0].appendChild(link);}
//动态执行 stylevar flag = true;if (flag) {var style = document.createElement('style');style.type = 'text/css';//var box= document.createTextNode(#box{background:red}'); IE 不支持//style.appendChild(box);document.getElementsByTagName('head')[0].appendChild(style);insertRule(document.styleSheets[0], '#box', 'background:red', 0);}function insertRule(sheet, selectorText, cssText, position) { //如果是非 IE if (sheet.insertRule) { sheet.insertRule(selectorText + "{" + cssText + "}", position); //如果是 IE } else if (sheet.addRule) { sheet.addRule(selectorText, cssText, position); }}
- [DOM]javascript DOM操作
- Javascript DOM
- javascript--dom
- JavaScript DOM
- Dom ,JavaScript
- Javascript DOM
- javascript Dom
- JavaScript DOM
- JavaScript Dom
- javascript-DOM
- Javascript -- DOM
- JavaScript/DOM
- JavaScript DOM
- JavaScript+DOM
- javascript dom
- javascript--DOM
- javascript DOM
- JavaScript DOM
- EventBus使用详解(一)——初步使用EventBus
- 在CI框架中如何发送email?
- jsp el simple
- MySql 安装报错 :Last Error:Unable to update security. Access denied for user 'root'@'localhost'(using pa
- StringIO的读写问题
- JavaScript DOM
- Duplication with Oracle Managed Files(OMF)
- 设计模式之模板模式
- 关于extjs
- swift-swicth广义匹配
- C++多维数组
- XML文件的解析
- Git 快速入门
- 安卓架构...有什么清晰的方式?