1 与类相关的扩充
HTML5 新增了很多致力于简化 CSS 类的用法。
1.1 getElementsByClassName()
可以在 document 对象以及所有的 HTML 元素上调用该方法。
它接受一个参数,即包含一个或者多个类名的字符串,返回带有指定类的所有元素的 NodeList。
//取得所有类中包含 “username” 和 “current” 的元素,与类型的顺序无关
var allCurrentUsernames = document.getElementsByClassName("username current");
//取得 ID 为 "myDiv" 的元素中带有类名 "selected" 的所有元素
var selected = document.getElementById("myDiv").getElementsByClassName("selected");
通过这个方法可以很方便地为带有某些类的元素添加事件处理程序。然而,因为返回的是 NodeList,所以要注意 NodeList 可能带来的性能问题。
支持 getElementsByClassName() 的浏览器有:
- IE 9+
- Firefox 3+
- Safari 3.1+
- Chrome
- Opera 9.5+
1.2 classList 属性
原来操作类名时,需要通过 className 属性添加、删除和替换类名。因为 className 是一个字符串,所以每次修改某一部分时,都要重新设置整个值。比如这个 HTML 代码:
<div class="bd user disabled">...</div>
假设要删除 user 类:
//取得类名字符串并拆分为数组
var classNames = div.className.split(/\s+/);
//找到要删除的类名
var pos = -1,
i,
len;
for (i=0, len=classNames.length; i < len; i++){
if (classNames[i] == "user"){
pos = i;
break;
}
}
//删除类名
classNames.splice(i,1);
//把剩下的类名拼成字符串并重新设置
div.className = classNames.join(" ");
很多 JavaScript 库都实现了这个方法,以便简化操作。
HTML5 为所有元素新增了 classList 属性,它是新集合类型 DOMTokenList 的实例。DOMTokenList 有一个 length 属性,表示包含的元素个数。可以使用 item() 或者方括号语法来取得每一个元素。此外它还定义了这些方法:
方法 | 说明 |
---|---|
add(value) | 将给定的字符串添加到列表中。如果已经存在,就不操作。 |
contains(value) | 列表中是否存在给定的值。如果存在,返回 true。 |
remove(value) | 从列表中删除给定的字符串。 |
toggle(value) | 如果列表中已经存在给定的值,就删除;如果列表中没有给定的值,就添加。 |
这些方法可以极大地减少基本操作的复杂度:
//删除 “disabled” 类
div.classList.remove("disabled");
//添加 “current” 类
div.classList.add("current");
//切换 “user” 类
div.classList.toggle("user");
//确定元素中是否包含既定的类名
if (div.classList.contains("bd") && !div.classList.contains("disabled")){
...
}
//迭代类名
for (var i=0, len=div.classList.length; i < len; i++){
doSomething(div.classList[i]);
}
支持 classList 属性的浏览器有:
- Firefox 3.6+
- Chrome
2 焦点管理
2.1 activeElement 属性
document.activeElement 属性,会引用 DOM 中当前获得焦点的元素。元素可以通过以下方法获得焦点:
- 页面加载
- 用户输入(Tab 键)
- 在代码中调用 focus()
var button = document.getElementById("myButton");
button.focus();
console.log(document.activeElement === button);//true
默认情况下,当文档刚刚加载完成,document.activeElement 中保存的是 document.body 元素。在文档加载期间,document.activeElement 是 null。
2.2 hasFocus()
它用来确定文档是否获得了焦点。
var button = document.getElementById("myButton");
button.focus();
console.log(document.hasFocus());//true
检查文档是否获得了焦点,可以获知用户是否正在与当前页面进行交互。
这两个功能都是为了提高 Web 应用的无障碍性。
支持 hasFocus() 的浏览器有:
- IE 4+
- Firefox 3+
- Safari 4+
- Chrome
- Opera 8+
3 HTMLDocument 的变化
3.1 readyState 属性
它有两个可能的值:
- loading,正在加载文档
- complete,已经加载完文档
通过它可以实现一个指示文档已经加载完成的指示器。
if (document.readyState == "complete"){
...
}
支持 readyState 属性的浏览器有:
- IE 4+
- Firefox 3.6+
- Safari
- Chrome
- Opera 9+
3.2 compatMode 属性
它表示的是浏览器采用了哪一种渲染模式。
模式 | document.compatMode 值 |
---|---|
标准 | CSS1Compat |
混杂 | BackCompat |
if (document.compatMode == "CSS1Compat"){
console.log("Standards mode");
} else {
console.log("Quirkss mode");
}
支持 compatMode 属性的浏览器有:
- IE 6+
- Firefox
- Safari 3.1+
- Chrome
- Opera
3.3 head 属性
它引用的是文档的 <head>
元素。跨浏览器的、获取文档 <head>
元素的方法是:
var head = document.head || document.getElementsByTagName("head")[0];
支持 compatMode 属性的浏览器有:
- Safari 5
- Chrome
4 字符集属性
4.1 charset 属性
表示文档中实际使用的字符集,也可以指定新的字符集。它的默认值是 “UTF-16”,也可以通过 <meta>
元素、响应头部或直接设置 charset 属性修改它:
console.log(document.charset);//UTF-16
document.charset = "UTF-8";
支持 charset 属性的浏览器有:
- IE
- Firefox
- Safari
- Opera
- Chrome
4.2 defalutCharset 属性
表示根据默认浏览器以及操作系统的设置,当前文档默认的字符集。如果设置了文档字符集,它就有可能于 defalutCharset 属性的值不同:
if (document.charset != document.defaultCharset){
console.log("Custom character set being used.");
}
支持 defalutCharset 属性的浏览器有:
- IE
- Safari
- Chrome
可以通过这两个属性得到文档当前使用的字符编码信息,也可以对它们进行控制。
5 自定义数据属性
HTML5 可以为元素添加非标准的属性,但要添加前缀 data-,目的是为了为元素提供与渲染无关的信息,或者提供语义信息:
<div id="myDiv" data-appId="12356" data-myname="Nicholas"></div>
可以提供元素的 dataset 属性来访问自定义属性的值。 dataset 属性是 DOMStringMap 的一个实例,是一个名值对的映射关系,这里的名没有带 “data-” 前缀哦:
var div = document.getElementById("myDiv");
//取得自定义属性的值
var appId = div.dataset.appId;
var myName = div.dataset.myname;
//设置值
div.dataset.appId=8989;
div.dataset.myname = "deniro";
if (div.dataset.myname){// myname 值存在
console.log("Hello, " + div.dataset.myname);
}
自定义数据属性,一般用于为元素添加一些不可见的数据以便进行其他的处理。在跟踪链接或者混搭应用中,可以通过设置自定义数据属性来方便地获知点击来自页面的哪一个部分。
支持 dataset 属性的浏览器有:
- Firefox 6+
- Chrome
6 插入标记
6.1 innerHTML 属性
读模式下,它返回与调用元素所有子节点(包括元素、注释以及文本节点)对应的 HTML 标记。写模式下,它会根据指定的值创建新的 DOM 树,然后用这个树完全替换调用元素原先的所有子节点。
不同的浏览器返回的文本格式会不同。
如果设置的值是纯文本,那么结果就是设置纯文本。
注意: 为 innerHTML 设置值之后,浏览器会将这个字符串解析为相应的 DOM 树。注意,从这个元素中,再次读取的 HTML 字符串,会与设置的值不一样!这是因为返回的字符串是根据新创建的 DOM 树序列化后的结果。
在大多数浏览器中,通过 innerHTML 插入 <script>
元素并不会执行其中的脚本。IE8 以及更早的版本可以通过这种方法执行脚本。不过它有这些限制:
- 必须为
<script>
元素指定 defer 属性。 <script>
元素必须位于有作用域的元素之后。
所以在 IE 中可以这样做:
div.innerHTML = "<input type=\"hidden\"><script defer>alert('hi');<\/script>";
因为隐藏的 <input>
域不会影响页面布局,所以是首选方式。
在 IE8 以及更早的版本中,<style>
也是一个没有作用域的元素,因为必须在它前面插入一个文本节点:
div.innerHTML = "_<style type\"text/css\">body {background-color: red; }</style>";
div.removeChild(div.firstChild);
这些元素不支持 innerHTML 属性:<col>、<colgroup>、<frameset>、<head>、<html>、<style>、<table>、<tbody>、<thead>、<tfoot>、<tr>
。在 IE8 以及更早的版本中,<title>
也不支持 innerHTML 属性。
注意: Firefox 对内容类型是 application/xhtml+xml
的 XHTML 文档中设置的 innerHTML 有严格的限制。写入 innerHTML 的 XHTML 代码必须完全符合要求,否则它会静默失败。
IE8 有一个 window.toStaticHTML() 方法,它接受一个参数,即 HTML 字符串;返回一个经过无害化处理的版本(从原来的 HTML 中删除所有脚本节点和事件处理程序)。
建议开发人员在通过 innerHTML 插入代码之前,先尽可能地检查一下其中的文本内容。
6.2 outerHTML 属性
在读模式下,outerHTML 返回调用它的元素以及所有的子节点的 HTML 标签。在写模式下,outerHTML 会根据指定的 HTML 字符串创建新的 DOM 子树,然后用这个 DOM 子树完全替换调用的元素。
<div id="content">
<p>This is a <strong>paragraph</strong> with a list following it.</p>
<ul>
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
</ul>
</div>
<script type="text/javascript">
var div = document.getElementById("content");
div.outerHTML = "<p>This is a paragraph.</p>";
</script>
支持 outerHTML 属性的浏览器有:
- IE4+
- Safari 4+
- Firefox 8+
- Chrome
- Opera 8+
6.3 insertAdjacentHTML 属性
它接受两个参数:插入位置和要插入的 HTML 文本。
插入位置的值 | 说明 |
---|---|
“beforebegin” | 在当前元素之前插入一个紧邻的同辈元素。 |
“afterbegin” | 在当前元素之下插入一个新的子元素,它位于原来第一个子元素之前 |
“beforeend” | 在当前元素之下插入一个新的子元素,它位于原来第一个子元素之后 |
“afterend” | 在当前元素之后插入一个紧邻的同辈元素。 |
插入位置的值必须是小写形式。如果浏览器无法解析这个值,它就会抛出错误。
支持 insertAdjacentHTML 属性的浏览器有:
- IE
- Safari
- Firefox 8+
- Chrome
- Opera
6.4 内存与性能问题
上面的这些属性和方法可能会导致浏览器的内存占用问题,这个问题在 IE 中特别明显。因此在使用 innerHTML 属性、outerHTML 属性和 insertAdjacentHTML() 方法时,最好先手工删除要被替换的元素的所有事件处理程序和 JavaScript 对象属性。
在插入大量新的 HTML 标记时,使用 innerHTML 属性比多次 DOM 操作效率高很多。因为浏览器会为新的 innerHTML 属性值或 outerHTML 属性值创建一个 HTML 解析器,这是浏览器级别的代码实现的(一般是 C++),因此它执行的很快。但创建和销毁 HTML 解析器也会带来性能的损失,所以最好将设置 innerHTML 或 outerHTML 的次数控制在合理的范围内,比如像这样创建多个列表项:
var itemsHtml = "";
for (var i=0, len=values.length; i < len; i++){
itemsHtml += "<li>" + values[i] + "</li>";
}
ul.innerHTML = itemsHTML;//一次性赋值
7 scrollIntoView()
它可以在所有的 HTML 元素上调用,让元素出现在视口中。它接受一个参数,如果是 true(默认),它会让调用元素的顶部与视口的顶部尽可能平齐;如果是 false,它会让调用元素尽可能全部出现在视口中(如果可能的话,会让调用元素的底部与视口顶部平齐)。
可以利用这个方法,吸引用户的注意。实际上,为某个元素设置焦点也会导致浏览器滚动并显示出获得焦点的元素。
document.forms[0].scrollIntoView();
支持 scrollIntoView() 的浏览器有:
- IE
- Safari
- Firefox
- Opera