1. Document Structure
再看上一章的html例子:
My home page
My home page
Hello, I am Marijn and this is my home page.
I also wrote a book! Read it
here.
这个HTML文档的结构
如下:
document
在js代码中,document是一个全局变量,它代表了整个HTML文档。 document.documentElement 就是 这个tag对应的对象。 document.head, document.body 分别对应 和 对象。
2. Trees
还记得第11章的语法树吗?那么多递归访问,把我转的晕头转向。DOM也是这样的语法树。树根是 document.documentElement。
上图中每一个方框都是node。node有多种类型(nodeType),每种类型在js中都有一个对应的常量值,常见的三种类型是:
1. regular elements:
document.ELEMENT_NODE: 1
上图中的灰色方框
2. text nodes:
document.TEXT_NODE: 3
上图中的淡蓝色方框
3. comments
document.COMMENT_NODE: 8
3. The Standard
DOM 不是专门为js设计的,甚至都不是专门为HTML设计的,它是一种语言中立的接口,或者说它是为XML设计的接口。而XML是一种更宽泛领域的超语言,HTML只是它的一个小应用。所以,后面会看到,我们在使用DOM操纵HTML时,经常会感觉有些别扭。例如,每一个element 都有childNodes属性,通过该属性可以访问它的所有子节点,而childNodes不是Array类型,它是NodeList类型,它没有slice和forEach方法。
如果操作DOM的行为比较多,代码会非常的冗长而难看。还好,已经有写第三方库提供了简单的方法,例如 jQuery。
4. Moving through the tree
上图描述了一个DOM结构,以及访问各个node的方法:
childNodes, parentNode, firstChild, previousSibling, nextSibling, lastChild
举个例子,在HTML中查找是否存在 "book" 这个单词:
function talksAbout(node, string) {
if (node.nodeType == document.ELEMENT_NODE) {
for (var i = 0; i < node.childNodes.length; i++) {
if (talksAbout(node.childNodes[i], string))
return true;
}
return false;
} else if (node.nodeType == document.TEXT_NODE) {
return node.nodeValue.indexOf(string) > -1;
}
}
console.log(talksAbout(document.body, "book"));
// → true
三个函数:
1. getElementsByTagName()
var link = document.body.getElementsByTagName("a")[0];
console.log(link.href);
2. getElementById()
My ostrich Gertrude:

3. getElementsByClassName()
这个函数和getElementsByTagName()类似。 ...
6. Changing the Document
functions:
removeChild()
appendChild()
insertBefore()
replaceChild()
例子:
One
Two
Three
一个node只能存在于一个位置,所以,把第2个p插入第0个p时,会先把它从原来的位置删除。
注意,replaceChild() 和 insertBefore() 的第一个参数是新插入的节点,第二个节点是参考位置的节点。7. Creating Nodes
先看个例子:
把 节点替换成Text节点,Text的内容是
的alt属性的值。
The
in the
.
用 document.createTextNode() 创建Text节点。
注意,getElementsByTagName()、getElementsByClassName() 和 childNodes 等得到的节点列表是 live 的,也就是说,当DOM结构发生变化之后,通过这些方法的node列表(上面的var images)也会随之变化。
所以,上面代码遍历images时,要从后往前遍历。
可以把live的节点列表变成solid(固定的):
var arrayish = {0: "one", 1: "two", length: 2};
var real = Array.prototype.slice.call(arrayish, 0);
real.forEach(function(elt) { console.log(elt); });
// → one
// two
第十一章也用过类似的方法:把一个 “像” 数组的对象转换成数组,因为它们的数据存储方式相同。
再看一个例子:
No book can ever be finished. While working on it we learn
just enough to find it immature the moment we turn away
from it.
使用 document.createElement(tag) 创建普通的节点。
8. Attributes
8.1. 有些节点的属性,在DOM中有相同名字的属性。
例如: 中的href。
var mylink = document.getElementById("mylink");
mylink.href="http://blog.csdn.net";
8.2. 有些节点属性在DOM中没有对应的属性
我们自己定义的属性也没有,所以,需要用 getAttribute 和 setAttribute 来访问:
The launch code is 00000000.
I have two feet.
我们自己定义的属性最好加上data-前缀,以避免命名冲突。
查找 中代码的关键字,把它们用粗体显示 ()
Here it is, the identity function:
function id(x) { return x; }
上面代码中,attribute的访问很容易理解,反倒是RegExp的使用方法有些费解。仔细看第11行和第17行的注释。
8.4. node的class属性
例如: ...
在DOM中class对应的属性是className,我们也可以用 getAttribute("class") 、setAttribute("class") 来访问它。
9. Layout
9.1. 类型
block:另起一行
, inline:不会另起一行 9.2. size offsetWith, offsetHeight:带border的宽和高 clientWith, clientHeight: 不带border的宽和高 9.3. 例子
I'm boxed in
getBoundingClientRect( ) pageXOffset, pageYOffset 9.6. 重新计算layout 改动DOM内容,读取position和size属性,或则调用getBoundingClientRect( ) 都需要重新计算layout,如果操作过于频繁(例如:在循环中),会导致性能很差,网页响应慢。 看个例子:
10.1. style 属性:
display:block; 自己占一行 display:inline; 自己不单独占一行 display:none; 隐藏 (不改变DOM结构) 例如:
Pretty text
中间带连接线的style,有两种访问方式: style["font-family"] style.fontFamily 11. Cascading Styles 11.1. cascading
多处设置的style合并到一起(三种地方:.css 文件, 11.2. selector tag
p { font-size: 16px; } class
.subtle { color: gray; }
#header { background: blue; } 匹配的越精确,优先级越高。下面的p.a.b#main 就比上面的 p 优先级高。 p > a { ... } 的第一级 类子节点 p a { ... } 下面所有级别的 类节点 12. Query Selectors 上面讲了用 tag、class 和 id 获取elements,也可以通过selector获取elements。 querySelectorAll(sel), 获取所有符合selector的elements,document.querySelectorAll(), element.querySelectorAll() querySelector(sel) 返回第一个符合条件的element 这两个方法返回的elements不是live的,不会随着DOM的变化而变化 例:
And if you go chasing
rabbits And you know you're going to fall Tell 'em a hookah smoking
caterpillar Has given you the call 13. Positioning and Animating style的position属性有三种类型: static 默认。从上到下,从左到右,在浏览器中流式布局。 relative top和left 相对于它的默认 (position:static时) 的位置
absolute top和left 相对于父节点的坐标。父节点的position不能是static。如果父节点是static,则向上层找父节点。如果找不到符合条件的父节点,则相对于document。
requestAnimationFrame(func) 这个函数告诉browser,下次刷新屏幕时,执行参数中的函数。浏览器大约每秒刷新60次屏幕。 注意,坐标后面一定要加上单位(px, em等),否则,设置无效。 14. Exercise: Build a Table
15. Exercise: Elements by Tag Name
,
9.4.
获取一个element的精确位置
10. Styling
10.2. display 类型:
10.3.
修改style
This text is displayed inline,
as a block, and
not at all.
/* p elements, with classes a and b, and id main */
p.a.b#main {
font-size: 20px;
}
这些是最常用的selector,还有一些更复杂的,不再一一列出。
一只猫沿着椭圆轨迹平移。
当然,我们也可以使用 setTimeout() 或 setInterval() 来定时移动,但,requestAnimationFrame() 可以获得更平滑的效果。
比在控制台打印table简单多了,因为,不再需要考虑布局问题。
function byTagName(node, tagName) {
var nodes = [];
if (node.nodeType == document.ELEMENT_NODE) {
if (node.tagName.toLowerCase() == tagName.toLowerCase()) {
nodes.push(node);
}
for (var i = 0; i < node.childNodes.length; i++) {
var eles = byTagName(node.childNodes[i], tagName);
nodes = nodes.concat(eles);
}
}
return nodes;
}