BOM
包括window对象,location对象,navigator对象,screen对象,history对象.
location 对象
这个对象独特的地方在于,它既是 window 的属性,也是 document 的属性。也就是说, window.location 和 document.location 指向同一个对象。
location 对象不仅保存着当前加载文 档的信息,也保存着把 URL 解析为离散片段后能够通过属性访问的信息。
操作地址
可以通过修改 location 对象修改浏览器的地址。最常见的是使用 assign()方法并传入一 个 URL.
1 | location.assign("http://www.wrox.com"); |
如果给 location.href 或 window.location 设置一个 URL,也会以同一个 URL 值调用 assign()方法。比 如,下面两行代码都会执行与显式调用 assign()一样的操作:
1 | window.location = "http://www.wrox.com"; |
在以前面提到的方式修改 URL 之后,浏览器历史记录中就会增加相应的记录。当用户单击“后退” 按钮时,就会导航到前一个页面。如果不希望增加历史记录,可以使用 replace()方法。这个方法接 收一个 URL 参数,但重新加载后不会增加历史记录。调用 replace()之后,用户不能回到前一页。比 如下面的例子:
1 |
|
**最后一个修改地址的方法是 reload()**,它能重新加载当前显示的页面。调用 reload()而不传参 数,页面会以最有效的方式重新加载。也就是说,如果页面自上次请求以来没有修改过,浏览器可能会 从缓存中加载页面。如果想强制从服务器重新加载,可以像下面这样给 reload()传个 true:
1 | location.reload(); // 重新加载,可能是从缓存加载 |
脚本中位于 reload()调用之后的代码可能执行也可能不执行,这取决于网络延迟和系统资源等因 素。为此,最好把 reload()作为最后一行代码。
navigator对象
检测插件
除 IE10 及更低版本外的浏览器,都可以通 过 plugins 数组来确定。这个数组中的每一项都包含如下属性。
name:插件名称。
description:插件介绍。
filename:插件的文件名。
length:由当前插件处理的 MIME 类型数量。
history对象
history 对象表示当前窗口首次使用以来用户的导航历史记录。因为 history 是 window 的属性, 所以每个 window 都有自己的 history 对象。
导航
go()方法可以在用户历史记录中沿任何方向导航,可以前进也可以后退。这个方法只接收一个参数, 这个参数可以是一个整数,表示前进或后退多少步。负值表示在历史记录中后退(类似点击浏览器的“后 退”按钮),而正值表示在历史记录中前进(类似点击浏览器的“前进”按钮)。下面来看几个例子:
1 | // 后退一页 |
DOM
节点层次
DOM Level 1 描述了名为 Node 的接口,这个接口是所有 DOM 节点类型都必须实现的。Node 接口 在 JavaScript中被实现为 Node 类型,在除 IE之外的所有浏览器中都可以直接访问这个类型。在 JavaScript 中,所有节点类型都继承 Node 类型,因此所有类型都共享相同的基本属性和方法。
每个节点都有 nodeType 属性,表示该节点的类型。节点类型由定义在 Node 类型上的 12 个数值 常量表示,节点类型可通过与这些常量比较来确定,比如:
1 | if (someNode.nodeType == Node.ELEMENT_NODE){ |
Node类型
节点关系
每个节点都有一个 childNodes 属性,其中包含一个 NodeList 的实例。NodeList 是一个类数组对象,用于存储可以按位置存取的有序节点。注意,NodeList 并不是 Array 的实例,但可以使用中括 号访问它的值,而且它也有 length 属性。NodeList 对象独特的地方在于,它其实是一个对 DOM 结 构的查询,因此 DOM 结构的变化会自动地在 NodeList 中反映出来。我们通常说 NodeList 是实时的 活动对象,而不是第一次访问时所获得内容的快照(后面的querySelectorAll()方法返回的NodeLis是快照,而不是实时的)。
1 | //以下两种方法都是获取节点的方法 |
使用 Array.prototype. slice()可以像前面介绍 arguments 时一样把 NodeList 对象转换为数组。
1 | let arrayOfNodes = Array.prototype.slice.call(someNode.childNodes,0); |
当然,使用 ES6 的 Array.from()静态方法,可以替换这种笨拙的方式:
1 | let arrayOfNodes = Array.from(someNode.childNodes); |
每个节点都有一个 parentNode 属性,指向其 DOM 树中的父元素。childNodes 中的所有节点都 有同一个父元素,因此它们的 parentNode 属性都指向同一个节点。此外,childNodes 列表中的每个 节点都是同一列表中其他节点的同胞节点。而使用 previousSibling 和 nextSibling 可以在这个列 表的节点间导航。这个列表中第一个节点的 previousSibling 属性是 null,最后一个节点的 nextSibling 属性也是 null,如下所示:
1 | if (someNode.nextSibling === null){ |
父节点和它的第一个及最后一个子节点也有专门属性:firstChild 和 lastChild 分别指向 childNodes 中的第一个和最后一个子节点。someNode.firstChild 的值始终等于 someNode. childNodes[0],而 someNode.lastChild 的值始终等于 someNode.childNodes[someNode. childNodes.length-1]。
操纵节点
- appendChild()
appendChild(),用于在 childNodes 列表末尾添加节点。如果把文档中已经存在的节点传给 appendChild(),则这个节点会从之前的位置被转移到新位置。 即使 DOM 树通过各种关系指针维系,一个节点也不会在文档中同时出现在两个或更多个地方。
- insertBefore()
如果想把节点放到 childNodes 中的特定位置而不是末尾,则可以使用 insertBefore()方法。 这个方法接收两个参数:要插入的节点和参照节点。调用这个方法后,要插入的节点会变成参照节点的 前一个同胞节点,并被返回。如果参照节点是 null,则 insertBefore()与 appendChild()效果相 同.
- replaceChild()
replaceChild()方法接收两个参数:要插入的节点和要替换的节点。要替换的节点会被返回并从文档 树中完全移除,要插入的节点会取而代之。
- removeChild()
要移除节点而不是替换节点,可以使用 removeChild()方法。这个方法接收一个参数,即要移除 的节点。被移除的节点会被返回.
以上四个方法都是通过父节点操纵其子元素.
其他方法
所有节点类型还共享了两个方法。**第一个是 cloneNode()**,会返回与调用它的节点一模一样的节 点。cloneNode()方法接收一个布尔值参数,表示是否深复制。在传入 true 参数时,会进行深复制, 即复制节点及其整个子 DOM 树。如果传入 false,则只会复制调用该方法的节点。复制返回的节点属 于文档所有,但尚未指定父节点,所以可称为孤儿节点(orphan)。
cloneNode()方法不会复制添加到 DOM 节点的 JavaScript 属性,比如事件处理程 序。这个方法只复制 HTML 属性,以及可选地复制子节点。除此之外则一概不会复制。
normalize()。这个方法唯一的任务就是处理文档子树中的文本节点。由于解析器实现的差异或 DOM 操作等原因,可能会出现并不包含文本的文本节点,或者文本节点之间互为同胞关系。在节点上调用 normalize()方法会检测这个节点的所有后代,从中搜索上述两种 情形。如果发现空文本节点,则将其删除;如果两个同胞节点是相邻的,则将其合并为一个文本节点。
Document 类型
特点
1 | nodeType 等于 9; |
Document 类型是 JavaScript 中表示文档节点的类型。在浏览器中,文档对象 document 是 HTMLDocument 的实例(HTMLDocument 继承 Document),表示整个 HTML 页面。document 是 window 对象的属性,因此是一个全局对象。
提供了两个访问子节点的快捷方式。第一个是 documentElement 属 性,始终指向 HTML 页面中的元素。虽然 document.childNodes 中始终有元素,但 使用 documentElement 属性可以更快更直接地访问该元素。
1 | <html> |
1 | let html = document.documentElement; // 取得对<html>的引用 |
作为 HTMLDocument 的实例,document 对象还有一个 body 属性,直接指向body元素。因为 这个元素是开发者使用最多的元素,所以 JavaScript 代码中经常可以看到 document.body,比如:
1 | let body = document.body; // 取得对<body>的引用 |
文档信息
1 | // 读取文档标题 |
URL 跟域名是相关的。比如,如果 document.URL 是 http://www.wrox.com/WileyCDA/,则 document.domain 就是 www.wrox.com。
在这些属性中,只有 domain 属性是可以设置的。出于安全考虑,给 domain 属性设置的值是有限制的。如果 URL包含子域名如 p2p.wrox.com,则可以将 domain 设置为”wrox.com”(URL包含“www” 时也一样,比如 www.wrox.com)。不能给这个属性设置 URL 中不包含的值,比如:
1 | // 页面来自 p2p.wrox.com |
当页面中包含来自某个不同子域的窗格()或内嵌窗格(<iframe)时,设置
document.domain 是有用的。因为跨源通信存在安全隐患,所以不同子域的页面间无法通过 JavaScript通信。此时,在每个页面上把 document.domain 设置为相同的值,这些页面就可以访问对方的 JavaScript对象了。比如,一个加载自 www.wrox.com 的页面中包含一个内嵌窗格,其中的页面加载自p2p.wrox.com。这两个页面的 document.domain 包含不同的字符串,内部和外部页面相互之间不能访问对方的 JavaScript 对象。如果每个页面都把 document.domain 设置为wrox.com,那这两个页面之间就可以通信了。
浏览器对 domain 属性还有一个限制,即这个属性一旦放松就不能再收紧。比如,把
document.domain 设置为”wrox.com”之后,就不能再将其设置回”p2p.wrox.com”,后者会导致错
误,比如:
1 | // 页面来自 p2p.wrox.com |
定位元素
**getElementById()**和 **getElementsByTagName()**就是 Document 类型提供的两个方法。
getElementsByTagName()返回包含零个或多个元素的 NodeList。在 HTML 文档中,这个方法返回一个 HTMLCollection 对象。考虑到二者都是“实时”列表,HTMLCollection 与 NodeList 是很相似的。HTMLCollection 对象还有一个额外的方法 namedItem(),可通过标签的 name 属性取得某一项 的引用。例如,假设页面中包含如下的元素:
1 | <img src="myimage.gif" name="myImage"> |
那么也可以像这样从 images 中取得对这个元素的引用:
1 | let myImage = images.namedItem("myImage"); |
对 HTMLCollection 对象而言,中括号既可以接收数值索引,也可以接收字符串索引。而在后台, 数值索引会调用 item(),字符串索引会调用 namedItem()。
HTMLDocument 类型上定义的获取元素的第三个方法是 **getElementsByName()**。getElementsByName()方法也返回 HTMLCollection。
Element 类型
特点
1 | nodeType 等于 1; |
所有这些都可以用来获取对应的属性值,也可以用来修改相应的值。比如有下面的 HTML 元素:
1 | <div id="myDiv" class="bd" title="Body text" lang="en" dir="ltr"></div> |
1 | let div = document.getElementById("myDiv"); |
取得属性
与属性相关的 DOM 方法 主要有 3 个:getAttribute()、setAttribute()和 removeAttribute()。
1 | let div = document.getElementById("myDiv"); |
这种获取属性的方法和前面的不一样,重点为class,前面为className,这里为class,即元素中定义的什么属性名就是什么
创建元素
可以使用 document.createElement()方法创建新元素。这个方法接收一个参数,即要创建元素 的标签名。
1 | let div = document.createElement("div"); |
可以使用 appendChild()、insertBefore()或 replaceChild()。 比如,以下代码会把刚才创建的元素添加到文档的元素中:
1 | document.body.appendChild(div); |
DOM编程
动态脚本
动态脚本就是在页面初始加载时不存在,之后又通过 DOM 包含的脚本。与对应的 HTML 元素一样,有两种方式通过