DOM扩展
Posted 奋飛
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了DOM扩展相关的知识,希望对你有一定的参考价值。
下述内容主要讲述了《javascript高级程序设计(第3版)》第11章关于“DOM扩展”。
尽管DOM作为API已经非常完善了,但是为了实现更多的功能,仍然会有一些标准或专有的扩展。对DOM的两个主要扩展是Selectors API(选择符API)和html5。
一、选择符API
Selectors API是由W3C发起制定的一个标准,致力于让浏览器原生支持CSS查询。其核心的两个方法:querySelector()
和querySelectorAll()
。
1. querySelector()方法
querySelector()
接受一个CSS选择符,返回与该模式匹配的第一个元素,如果没有找到匹配的元素返回null。
示例:
document.querySelector("body");
document.querySelector("#content");
document.querySelector(".bd");
2. querySelectorAll()方法
querySelectorAll()接受一个CSS选择符,返回与该模式匹配的NodeList实例,如果没有找到匹配的元素返回null。
示例:
var lis = document.querySelectorAll("ul li");
// 获取第一个li
lis.item(0); // 等价于:lis[0];
注意:上述两个函数如果传入不支持的选择符,会抛出错误。
3. matchesSelector()方法
matchesSelector()
方法大部分浏览器未实现,可使用matches()或者使用各个浏览器实验性的实现。
function matchesSelector(element, selec)
如果调用元素与该选择符匹配,返回true;否则,返回false。
function matchesSelector(element, selector){
if (element.matchesSelector){
return element.matchesSelector(selector);
} else if (element.msMatchesSelector){
return element.msMatchesSelector(selector);
} else if (element.mozMatchesSelector){
return element.mozMatchesSelector(selector);
} else if (element.webkitMatchesSelector){
return element.webkitMatchesSelector(selector);
} else if(ele.matches){
return ele.matches(selector);
} else{
throw new Error("Not supported.");
}
}
matchesSelector(document.body, "body"); // true
matchesSelector(document.body, "body div"); // false
二、元素遍历
对于元素间的空格,各浏览器对于childNodes和firstChild等属性处理行为不一致,为了弥补差异,Element Traversal新定义了一组属性。
示例:
<p>李刚</p>
<ul>
<li>item1</li>
<li>item2</li>
<li>item3</li>
<li>item4</li>
<li>item5</li>
</ul>
<p id="blog">http://blog.csdn.net/ligang2585116</p>
属性 | 说明 | 示例 |
---|---|---|
childElementCount | 子元素(不包含文本节点和注释)的个数 | 5 |
firstElementChild | 指向第一个子元素,firstChild的元素版 | <li>Item 1</li> |
lastElementChild | 指向最后一个子元素,lastChild的元素版 | <li>Item 5</li> |
previousElementSibling | 指向前一个同辈元素,previousSibling的元素版 | <p>李刚</p> |
nextElementSibling | 指向后一个同辈元素,nextSibling的元素版 | <p id="blog">http://blog.csdn.net/ligang2585116</p> |
var ul = document.querySelector("ul");
ul.firstChild; // #text
ul.lastChild; // <li>Item 5</li>
ul.previousSibling; // #text
ul.nextSibling; // #text
三、HTML5
1. 与类相关的扩充
(1)getElementsByClassName("包含一或多个类名的字符串")
document.getElementsByClassName("bj"); // 取得类中包含“bj”的元素
document.getElementsByClassName("bj bd"); // 取得类中同时包含“bj”和“bd”的元素
(2)classList属性
在操作类名时,需要通过className属性添加、删除和替换类型名。因为className中是一个字符串,所以即使只修改字符串的一部分,也必须每次都设置整个字符串的值。
<div class="bd user">ligang</div>
示例:className方式
var div = document.getElementsByClassName("bd")[0];
var classNames = div.className.split(/\\s+/);
// 查找要删除的类名"user"
var index = classNames.indexOf("user");
// 删除类名"user"
classNames.splice(index, 1);
// 重新设置className
div.className = classNames;
示例:classList方式
var div = document.getElementsByClassName("bd")[0];
div.classList.remove("user");
classList属性是DOMTokenList的实例,其含有length属性。
属性 | 说明 |
---|---|
add(value) | 将给定的字符串添加到列表中。如果已存在,就不添加了 |
contains(value) | 表示列表中是否存在给定的值 |
remove(value) | 从列表中删除给定的字符串 |
toggle(value) | 如果列表中已存在给定的值,删除它;如果不存在,添加它 |
有了classList属性,除非需要删除全部所有类名,或者完全重写元素的class属性,否则也就用不到className属性了。
2. 焦点管理
document.activeElement
属性始终会引用DOM中当前获得了焦点的元素。
示例:
var btn = document.getElementById("myBtn");
btn.focus();
console.log(btn.hasFocus()); // true
console.log(document.activeElement === btn); // true
默认情况下,文档刚刚加载完成时,document.activeElement
中保存的是document.body
元素的引用。文档加载期间,document.activeElement
为null。
查询文档获知哪个元素获得了焦点,以及确定文档是否获得了焦点,这两个功能最重要的用途是提高Web应用的无障碍性。无障碍Web应用的一个重要标志就是恰当的焦点管理,而确切地知道哪个元素获得了焦点是一个极大的进步。
3. HTMLDocument的变化
(1)readyState属性
- loading:正在加载文档;
- complete:已经加载完文档。
使用document.readyState的最恰当方式,就是通过它来实现一个指示文档已经加载完成的指示器。
(2)兼容模式
document.compatMode
告知开发人员浏览器采用了哪种渲染模式。
- CSS1Compat:标准模式;
- BackCompat:混杂模式。
(3)head属性
HTML5新增了document.head
属性,引用文档的<head>
元素。
var head = document.head || document.getElementsByTagName("head")[0];
4. 字符集属性
- document.charset:文档中实际使用的字符集,也可以用来指定新字符集;
- document.defaultCharset:表示根据浏览器及操作系统的设置,当前文档默认的字符集应该是什么,注意兼容性。
5. 自定义数据属性
HTML5规定可以为元素添加非标准的属性,但要添加前缀data-,目的是为元素提供与渲染无关的信息,或者提供语义信息。
<div id="div" data-status="1" data-appId="123" data-customName="ligang">哈哈</div>
添加了自定义属性后,可以通过元素的dataset属性来访问自定义属性的值。
var div = document.getElementById("div");
var dataset = div.dataset;
console.log(dataset.appid); // 123
console.log(dataset.customname); // "ligang" 注意,都是小写
6. 插入标记
DOM操作文档插入HTML标记非常复杂,因为其不仅要创建一系列DOM节点,而且还要小心地按照正确顺序进行连接。详见:DOM
示例:创建a标签并插入到body
var a = document.createElement("a");
a.href = "http://blog.csdn.net/ligang2585116";
a.text = "http://blog.csdn.net/ligang2585116";
document.body.appendChild(a);
使用插入标记的技术,直接插入HTML字符串不仅简单而且速度更快。
(1)innerHTML属性
读模式:返回调用元素的所有节点(包括元素、注释和文本节点)对应的HTML标记;
写模式:根据指定的值创建新的DOM树,然后用这个DOM树完全替换调用元素原先的所有子节点。
示例:创建a标签并插入到body
document.body.innerHTML += '<a href="http://blog.csdn.net/ligang2585116">http://blog.csdn.net/ligang2585116</a>'
注意:上述使用“+=”,因为写模式下,innerHTML的值会被解析为DOM子树,替换调用元素原来的所有子节点。
说明:使用innerHTML插入的字符串开头是一个无作用域的元素(<script>、<style>
)时,IE会在解析这个字符串前先删除该元素。
div.innerHTML = "<script>console.logt('hi')</script>"; // 无效
div.innerHTML = "<div> </div><script>console.logt('hi')</script>"; // 有效
div.innerHTML = "<input type=\\"hidden\\"><script>console.logt('hi')</script>"; // 有效
(2)outerHTML属性
读模式:返回调用它的元素及所有节点(包括元素、注释和文本节点)对应的HTML标记;
写模式:根据指定的值创建新的DOM树,然后用这个DOM树完全替换调用元素。
示例:
<div id="blog">
<!-- blog address -->
<a href="http://blog.csdn.net/ligang2585116">blog</a>
</div>
var div = document.getElementById("blog");
div.outerHTML; // 整个innerHTML内容+div本身
div.outerHTML = "<a href=\\"http://blog.csdn.net/ligang2585116\\">blog</a>"; // 整个div会被a标签替换掉
// 等价于
var a = document.createElement("a");
a.href = "http://blog.csdn.net/ligang2585116";
a.text = "blog";
div.parentNode.replaceChild(a, div);
(3)内存与性能问题
使用上述节点方法可能会导致浏览器的内存占用问题。在删除带有事件处理程序或引用了其他JavaScript对象子树时,就会导致内存占用问题。在使用innerHTML、outerHTML等方法时,最好先删除要替换的元素的所有事件处理程序和JavaScript对象属性。
7. scrollIntoView()方法
如何滚动页面也是DOM规范没有解决的一个问题,HTML5最终选择了scrollIntoView
作为标准。
scrollIntoView()
可以在任何元素上调用。默认或传入true,窗口会滚动让调用元素与视口顶部尽可能齐平;传入false,调用元素尽可能会全部出现在窗口中。
document.forms[0].scrollIntoView();
当页面发生变化时,一般会用这个方法来吸引用户的注意力。实际上,为某个元素设置焦点也会导致浏览器滚动并显示出获得焦点的元素。
四、专有扩展
1. children属性
children属性与childNodes没有什么区别。
2. contains()方法
判断某个节点是不是另一个节点的后代。
document.body.contains(div); // true
掩码 | 节点关系 |
---|---|
1 | 无关(给定的节点不再当前文档中) |
2 | 居前(给定的节点在DOM树中位于参考节点之前) |
4 | 居后(给定的节点在DOM树中位于参考节点之后) |
8 | 包含(给定的节点是参考节点的祖先) |
16 | 被包含(给定的节点是参考节点的后代) |
示例:通用的contains函数
function contains(refNode, otherNode){
if (typeof refNode.contains == "function" &&
(!client.engine.webkit || client.engine.webkit >= 522)){
return refNode.contains(otherNode);
} 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;
}
}
console.log(contains(document.documentElement, document.body)); // true
3. 插入文本
innerText
和outerText
并没有被纳入HTML5。
其对文本进行操作,使用方式类似于innerHTM
和outerHTML
。
4. 滚动
HTML5将scrollIntoView()方法纳入规范之后,仍还有其他几个专有方法可以在不同的浏览器中使用。
(1)scrollIntoViewIfNeeded(alignCenter)
:只在当前元素视口中不可见的情况下,才滚动浏览器窗口或容器元素,最终让它可见。如果当前元素在视口中可见,这个方法什么也不做。true,尽量将元素在显示视口中部(垂直方向)。
(2)scrollByLines(lineCount)
:将元素的内容滚动指定的行高。
(3)scrollByPages(pageCount)
:将元素的内容滚动指定的页面高度,具体高度由元素的高度决定。
注意:scrollIntoView()
和scrollIntoViewIfNeeded()
的作用对象是元素的容器;scrollByLines()
和scrollByPages()
影响的则是元素自身。
以上是关于DOM扩展的主要内容,如果未能解决你的问题,请参考以下文章
getSupportFragmentManager() 在活动扩展片段中未定义