JavaScript高级程序设计学习笔记第十一章--DOM扩展
1.对 DOM 的两个主要的扩展是 Selectors API(选择符 API)和 HTML5
2.Selectors API Level 1 的核心是两个方法: querySelector()和 querySelectorAll()。
3.querySelector():方法接收一个 CSS 选择符,返回与该模式匹配的第一个元素,如果没有找到匹配的元素,返回 null。用法如下:
1 //取得 body 元素 2 var body = document.querySelector("body"); 3 //取得 ID 为"myDiv"的元素 4 var myDiv = document.querySelector("#myDiv"); 5 //取得类为"selected"的第一个元素 6 var selected = document.querySelector(".selected"); 7 //取得类为"button"的第一个图像元素 8 var img = document.body.querySelector("img.button");
通过 Document 类型调用 querySelector()方法时,会在文档元素的范围内查找匹配的元素。而通过 Element 类型调用 querySelector()方法时,只会在该元素后代元素的范围内查找匹配的元素。
querySelectorAll():方法接收的参数与 querySelector()方法一样,都是一个 CSS 选择符,但返回的是所有匹配的元素而不仅仅是一个元素。这个方法返回的是一个 NodeList 的实例(一张快照,不是动态查询的结果)。如果没有找到匹配的元素, NodeList 就是空的。
能够调用 querySelectorAll()方法的类型包括 Document、DocumentFragment 和 Element。
要取得返回的 NodeList 中的每一个元素,可以使用 item()方法,例如: strongs.item(i) 也可以使用方括号语法,例如: strong = strongs[i];
matchesSelector():适用于Element 类型,这个方法接收一个参数,即 CSS 选择符,如果调用元素与该选择符匹配,返回 true;否则,返回 false。例如:
1 if (document.body.matchesSelector("body.page1")){ 2 //true 3 }
在取得某个元素引用的情况下,使用这个方法能够方便地检测它是否会被 querySelector()或querySelectorAll()方法返回。
元素遍历:对于元素间的空格,就会有在使用 childNodes 和 firstChild 等属性时的行为不一致。
- childElementCount:返回子元素(不包括文本节点和注释)的个数。
- firstElementChild:指向第一个子元素; firstChild 的元素版。
- lastElementChild:指向最后一个子元素; lastChild 的元素版。
- previousElementSibling:指向前一个同辈元素; previousSibling 的元素版。
- nextElementSibling:指向后一个同辈元素; nextSibling 的元素版。
HTML5中的DOM扩展:
getElementsByClassName():HTML5 添加的 getElementsByClassName()方法,接收一个参数,即一个包含一或多个类名的字符串,返回带有指定类的所有元素的 NodeList。传入多个类名时,类名的先后顺序不重要。例如:
1 //取得所有类中包含"username"和"current"的元素,类名的先后顺序无所谓 2 var allCurrentUsernames = document.getElementsByClassName("username current"); 3 //取得 ID 为"myDiv"的元素中带有类名"selected"的所有元素 4 var selected = document.getElementById("myDiv").getElementsByClassName("selected");
在 document 对象上调用getElementsByClassName()始终会返回与类名匹配的所有元素,在元素上调用该方法就只会返回后代元素中匹配的元素。
classList 属性:HTML5 新增了一种操作类名的方式,新集合类型 DOMTokenList 的实例。DOMTokenList 有一个表示自己包含多少元素的 length 属性,而要取得每个元素可以使用 item()方法,也可以使用方括号语法。此外,这个新类型还定义如下方法。
- add(value):将给定的字符串值添加到列表中。如果值已经存在,就不添加了。
- contains(value):表示列表中是否存在给定的值,如果存在则返回 true,否则返回 false。
- remove(value):从列表中删除给定的字符串。
- toggle(value):如果列表中已经存在给定的值,删除它;如果列表中没有给定的值,添加它。
使用方法如下:
1 //删除"user"类 2 //首先,取得类名字符串并拆分成数组 3 var classNames = div.className.split(/\s+/); 4 //找到要删的类名 5 var pos = -1, 6 i, 7 len; 8 for (i=0, len=classNames.length; i < len; i++){ 9 if (classNames[i] == "user"){ 10 pos = i; 11 break; 12 } 13 } 14 //删除类名 15 classNames.splice(i,1); 16 //把剩下的类名拼成字符串并重新设置 17 div.className = classNames.join(" ");
以上代码采用classList只用下面一行就可以了: div.classList.remove("user");
辅助管理 DOM 焦点的功能:
document.activeElement 属性:这个属性始终会引用 DOM 中当前获得了焦点的元素。
元素获得焦点的方式有页面加载、用户输入(通常是通过按 Tab 键)和在代码中调用 focus()方法。例如:
1 var button = document.getElementById("myButton"); 2 button.focus(); 3 alert(document.activeElement === button); //true
默认情况下,文档刚刚加载完成时, document.activeElement 中保存的是 document.body 元素的引用。文档加载期间, document.activeElement 的值为 null。
document.hasFocus()方法:新增的方法,这个方法用于确定文档是否获得了焦点。
1 var button = document.getElementById("myButton"); 2 button.focus(); 3 alert(document.hasFocus()); //true
文档中的元素button获得了焦点,这样就可以算作文档获得了焦点
HTMLDocument的变化:
readyState 属性:Document 的 readyState 属性有两个可能的值:
- loading,正在加载文档;
- complete,已经加载完文档。
检测页面的兼容模式就成为浏览器的必要功能。IE 为此给 document 添加了一个名为 compatMode 的属性,这个属性就是为了告诉开发人员浏览器采用了哪种渲染模式。在标准模式下, document.compatMode 的值等于"CSS1Compat",而在混杂模式下, document.compatMode 的值等于"BackCompat"。
document.head 属性:用来引用文档的<head>元素,可以使用下面的方法, var head = document.head || document.getElementsByTagName("head")[0];
字符集属性:
- charset 属性:示文档中实际使用的字符集,也可以用来指定新字符集。默认情况下,这个属性的值为"UTF-16"。但可以通过<meta>元素、响应头部或直接设置 charset 属性修改这个值。例如: alert(document.charset); //"UTF-16" document.charset = "UTF-8";
- defaultCharset属性:表示根据默认浏览器及操作系统的设置,当前文档默认的字符集应该是什么。如果文档没有使用默认的字符集,那 charset 和 defaultCharset 属性的值可能会不一样。
自定义属性:
HTML5 规定可以为元素添加非标准的属性,但要添加前缀 data-,目的是为元素提供与渲染无关的信息,或者提供语义信息。这些属性可以任意添加、随便命名,只要以 data-开头即可。添加了自定义属性之后,可以通过元素的 dataset 属性来访问自定义属性的值。 dataset 属性的值是 DOMStringMap 的一个实例,也就是一个名值对儿的映射。在这个映射中,每个 data-name 形式的属性都会有一个对应的属性,只不过属性名没有 data-前缀(比如,自定义属性是 data-myname,那映射中对应的属性就是 myname)。例如:
1 <div id="myDiv" data-appId="12345" data-myname="Nicholas"></div> 2 var div = document.getElementById("myDiv"); 3 //取得自定义属性的值 4 var appId = div.dataset.appId; 5 var myName = div.dataset.myname; 6 //设置值 7 div.dataset.appId = 23456; 8 div.dataset.myname = "Michael";
插入标记:
- innerHTML 属性:在读模式下, innerHTML 属性返回与调用元素的所有子节点(包括元素、注释和文本节点)对应的 HTML 标记。在写模式下, innerHTML 会根据指定的值创建新的 DOM 树,然后用这个 DOM 树完全替换调用元素原先的所有子节点。
- 不要指望所有浏览器返回的 innerHTML 值完全相同。
- 在写模式下, innerHTML 的值会被解析为 DOM 子树,替换调用元素原来的所有子节点。因为它的值被认为是 HTML,所以其中的所有标签都会按照浏览器处理 HTML 的标准方式转换为元素(同样,这里的转换结果也因浏览器而异)。
- 为 innerHTML 设置的包含 HTML 的字符串值与解析后 innerHTML 的值大不相同。例如设置如下:div.innerHTML = "Hello & welcome, <b>\"reader\"!</b>"; ,解析之后的结果如下:<div id="content">Hello & welcome, <b>"reader"!</b></div>原因在于返回的字符串是根据原始 HTML 字符串创建的 DOM 树经过序列化之后的结果。
- 使用 innerHTML 属性也有一些限制。比如,在大多数浏览器中,通过 innerHTML 插入<script>元素并不会执行其中的脚本。
- outerHTML 属性:在读模式下, outerHTML 返回调用它的元素及所有子节点的 HTML 标签。在写模式下, outerHTML会根据指定的 HTML 字符串创建新的 DOM 子树,然后用这个 DOM 子树完全替换调用元素。例如:
-
1 <div id="content"> 2 <p>This is a <strong>paragraph</strong> with a list following it.</p> 3 <ul> 4 <li>Item 1</li> 5 <li>Item 2</li> 6 <li>Item 3</li> 7 </ul> 8 </div>
如果在<div>元素上调用 outerHTML,会返回与上面相同的代码,包括<div>本身。不过,由于浏览器解析和解释 HTML 标记的不同,结果也可能会有所不同。
使用 outerHTML 属性以下面这种方式设置值:div.outerHTML = "<p>This is a paragraph.</p>";结果,就是新创建的<p>元素会取代 DOM 树中的<div>元素。 - insertAdjacentHTML()方法:接收两个参数:插入位置和要插入的 HTML 文本。第一个参数必须是下列值之一:
- "beforebegin",在当前元素之前插入一个紧邻的同辈元素;
- "afterbegin",在当前元素之下插入一个新的子元素或在第一个子元素之前再插入新的子元素;
- "beforeend",在当前元素之下插入一个新的子元素或在最后一个子元素之后再插入新的子元素;
- "afterend",在当前元素之后插入一个紧邻的同辈元素。
scrollIntoView()方法:scrollIntoView()可以在所有 HTML 元素上调用,通过滚动浏览器窗口或某个容器元素,调用元素就可以出现在视口中。如果给这个方法传入 true 作为参数,或者不传入任何参数,那么窗口滚动之后会让调用元素的顶部与视口顶部尽可能平齐。如果传入 false 作为参数,调用元素会尽可能全部出现在视口中,(可能的话,调用元素的底部会与视口顶部平齐。)不过顶部不一定平齐.
专有扩展:
- 文档模式
- children属性:这个属性是 HTMLCollection 的实例,只包含元素中(同样还是元素)的子节点。即在元素只包含元素子节点时,children 属性与 childNodes 没有什么区别。
- contains()方法:调用 contains()方法的应该是祖先节点,也就是搜索开始的节点,这个方法接收一个参数,即要检测的后代节点。如果被检测的节点是后代节点,该方法返回 true;否则,返回 false。
- 插入文本:
- innertText 属性可以操作元素中包含的所有文本内容,包括子文档树中的文本。在通过innerText 读取值时,它会按照由浅入深的顺序,将子文档树中的所有文本拼接起来。在通过innerText 写入值时,结果会删除元素的所有子节点,插入包含相应文本值的文本节点。例如:
1 <div id="content"> 2 <p>This is a <strong>paragraph</strong> with a list following it.</p> 3 <ul> 4 <li>Item 1</li> 5 <li>Item 2</li> 6 <li>Item 3</li> 7 </ul> 8 </div> 9 InnerTextExample01.ht
读取这个div的innerText的时候:返回This is a paragraph with a list following it.
使用 innerText 属性设置这个<div>元素的内容的时候: div.innerText = "Hello world!"; ,得到的页面的HTML的代码是 <div id="content">Hello world!</div> ,设置该属性移除了先前存在的所有子节点,完全改变了 DOM子树。
Item 1
Item 2
Item 3
设置 innerText 永远只会生成当前节点的一个子文本节点,而为了确保只生成一个子文本节点,
就必须要对文本进行 HTML 编码。利用这一点,可以通过 innerText 属性过滤掉 HTML 标签。方法是
将 innerText 设置为等于 innerText,这样就可以去掉所有 HTML 标签,例如: div.innerText = div.innerText; - outerText 属性:作用范围扩大到了包含调用它的节点,在读取文本值时, outerText 与 innerText 的结果完全一样。但在写模式下, outerText 就完全不
同了: outerText 不只是替换调用它的元素的子节点,而是会替换整个元素(包括子节点)。
- innertText 属性可以操作元素中包含的所有文本内容,包括子文档树中的文本。在通过innerText 读取值时,它会按照由浅入深的顺序,将子文档树中的所有文本拼接起来。在通过innerText 写入值时,结果会删除元素的所有子节点,插入包含相应文本值的文本节点。例如:
- 滚动