js高程读书笔记 第十一章 DOM拓展

[TOC]

本章内容

  • 理解Selectors API
  • 使用HTML5 DOM拓展
  • 了解专有的DOM拓展

选择符API

querySelector()和querySelectorAll()

其中querySelectorAll()放回的是带有所有属性和方法的NodeList,而其底层类似于一组元素的快照,而非不断对文档进行搜索的动态查询。

machesSelector()方法

如果调用的元素与该选择符匹配,返回true

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function matchesSelector(elememt, 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{
throw new Error("Not supported.");
}
}

if(matchesSelector(document.body, 'body.page1')){
//操作
}

元素遍历

IE9以及之前,元素间的空格会被认成文本节点。需要判断nodeType == 1来筛选元素。

新元素遍历规范Element Traversal规范定义了一组属性

  • childElementCount
  • firstElementChild 对应firstChild元素版
  • lastElementChild 对应lastChild元素版
  • previousElementSibling 对应previousSibling元素版
  • nextElementSibling 对应nextSibling元素版

HTML5

与类相关的扩充

getElementsByClassName()方法接收类名,返回NodeList

1
2
3
4
//获取所有类中包含“username”和current的元素
var allCurrentUsernames = document.getElementsByClassName("username current");
//取得ID为myDiv元素中带有类名selected的所有元素
var selected = document.getElementById("myDIv").getElementsByClassName("selected");

classList属性

在操作类名时,className属性添加、删除和替换类名。

1
<div class="bd user disabled">...</div>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//删除user类

//取得类名字符串并拆分成数组
var classNames = div.className.split(/\s+/);

//找到要删的类名
var pos = -1,
i,
len;
for(i = 0, len = classNames.length; i < len; i++){
if(className[i] == "user"){
pos = i;
break;
}
}

//删除类名
classNames.splice(i,1);

//把剩下的类名拼成字符串并重新设置
div.className = className.join(" ");

HTML5 新增一种操作类名的方式,所有的元素添加了classList属性,是新集合类型DOMTokenList的实例。

  • add(value) 将给定字符串添加到列表中
  • contains(Value) 存在值返回true
  • remove(value) 删除给定字符串
  • toggle(value) 如果列表中已经存在给定的值,删除它;没有给定的值,添加它。

前面这么多行用一行就可以代替了

1
div.classList.remove("user");

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//删除"disabled"类
div.classList.remove("disabled");

//添加"添加current"类
div.classList.toggle("user");

//确定元素中是否包含既定的类名
if(div.classList.contain("bd") && !div.classList.contains("disabled")){
//执行操作
}

//迭代类名
for(var i = 0,len = div.classList.length;i < len; i++){
doSomething(div.classList[i]);
}

焦点管理

元素获得焦点的方式有页面加载、用户输入(通常tab键)和代码中调用focus()方法。

默认情况下,文档刚刚加载完成时,document.activeElement中保存的是document.body元素。加载期间其值为null。

新增document.hasFocus()方法用来确定文档是否获得了焦点。

HTMLDocument的变化

readyState属性

  • loading 正在加载文档
  • complete 已经加载完文档
1
2
3
if(document.readyState == "complete"){
//执行操作
}

兼容模式

标准\混杂

1
2
3
4
5
if(document.compatMode == "CSS1Compat"){
console.log("标准模式standard")
}else if(document.compatMode == "BackCompat"){
console.log("混合模式quirks")
}

head属性

引用文档<head>元素

1
var head = document.head || document.getElementsByTagName("head")[0];

字符集属性

charset属性表示文档中实际使用的字符集。默认情况的值为“UTF-16”。可以通过<meta>元素,响应头部或直接设置charset属性修改这个值。

1
2
console.log(document.charset);//"UTF-16"
document.charset = "UTF-8";

另一个值是defaultCharset,表示根据默认浏览器及操作系统的设置。

自定义数据属性

HTML5规定可以为元素添加非标准的属性,但要添加前缀data-,目的是为元素提供与渲染无关的信息,或者提供语义信息。

1
<div id="myDiv" data-appId="12345" data-myname="Nicholas"></div>

可以通过元素的dataset属性来访问自定义属性的值。dataset属性的值是DOMStringMap的一个实例,也就是一个名值对的映射。

1
2
3
4
5
6
7
8
9
10
11
12
var div = document.getElementById("myDiv");

var appId = div.dataset.appId;
var myname = div.dataset.myname;

//设置值
div.dataset.appId = 23456;
div.dataset.myname = "Nicholas";

if(div.dataset.myname){
console.log("Hello, "+ div.dataset.myname);
}

插入标记

innerHTML属性

在写模式下,innerHTML的值会被解析为DOM子树,替换调用元素原来的所有子节点。

大多数浏览器中,通过innerHTML插入<script>元素并不会执行其中的脚本。IE8及更早版本是唯一能在这种情况下执行脚本的浏览器。需要满足一、为<script>指定defer属性,二、<script>元素必须位于“有作用域的元素”,也就是在页面中看得到的元素。

outerHTML属性

outerHTML返回调用它的元素及所有子节点的HTML标签。

使用outerHTML属性设置值,会取代原来的元素。

insertAdjacentHTML()方法

接收两个参数,插入位置和要插入的HTML文本。

  • beforebegin 在当前元素之前插入一个紧邻的同辈元素
  • afterbegin 在当前元素之下插入一个新的子元素或者在第一个子元素之前再插入新的子元素
  • beforeend 在当前元素之下插入一个新的子元素或者在最后一个子元素之后再插入新的子元素
  • afterend 在当前元素之后插入一个紧邻的同辈元素。

内存与性能问题

在删除带有时间处理程序或者引用了其他JavaScript对象子树时,元素与事件处理程序之间的绑定关系在内存中并没有一并删除。在使用innerHTML、outerHTML和insertAdjacentHTML()方法时,最好先手工删除要被替换的元素的所有事件处理程序和JavaScript对象属性。

使用innerHTML与之前多次创建DOM节点再指定他们的关系相比,效率更高(解析器是浏览器级别的代码,通常是C++)。不过最好也能够将设置innerHTML或outerHTML的次数控制在合理的范围内。

scrollIntoView()方法

传入true为参数,或者不传入任何参数,窗口会滚动至让调用元素的顶部与视口顶部平齐。如果传入false作为参数,调用元素会尽可能全部出现在视口中。

专有拓展

文档模式

children属性

contains()方法

调用这个方法的是祖先节点。这个方法接收一个参数,即要检测的后代节点。如果是后代节点则返回true。

DOM Level 3 compareDocumentPosition()也能确定节点间的关系。返回一个表示该关系的位掩码。

掩码 节点关系
1 无关
2 居前
4 局后
8 包含(给定的节点是参考节点的祖先)
16 被包含(给定节点是参考节点的后代)

插入文本

innerText属性会过滤html标签

outerText属性将作用范围扩大到了包含调用它的节点之外。

滚动

  • scrollIntoViewIfNeeded(alignCenter) 如果不可见才滚动,参数设置true表示尽量将元素显示在视口中部
  • scrollByLines() 将元素的内容滚动指定行高
  • scrollByPages() 将元素的内容滚动指定页面高度

小结

  • Selector API 提供了 querySelector()和querySelectorAll()方法
  • Element Traversal 为DOM元素定义了额外的属性
  • HTML5 innerHTML,管理焦点,设置字符集、页面滚动等等