JavaScript高级程序设计学习11_DOM扩展

1、HTML5

1、classList属性

在操作类名时,需要通过className属性添加、删除和替换。因为className中是一个字符串,即使只修改一部分,也必须设置整个字符串。

add(value):将给定的字符串添加到列表中。如果存在,就不添加了

contains(value):判断是否存在给定的值。返回true或false

remove(value):从列表中删除给定的字符串

toggle(value):如果列表中存在给定的值,删除它;如不存在,添加

2、焦点管理

HTML5也添加了辅助管理DOM焦点的功能。元素获取焦点的方式有页面加载、用户输入(通常是Tab键)和在代码中使用focus()方法。

document.activeElement属性:始终会引用DOM中当前获得了焦点的元素

document.hasFocus():用于确定文档是否获得了焦点,如下例:

let button = document.getElementById("myBtn");
button.focus();

/**默认情况下,文档刚刚加载完,document.activeElement保存的是document.body元素的引用。文档加载期间。它的值为null*/
alert(document.activeElement === button);//true

/**文档新增了document.hasFocus()方法,用于确定文档是否获得了焦点,可以知道用户是不是正在与页面进行交互*/
alert(document.hasFocus());//true

查询文档获知哪个元素获得了焦点,以及是否获得了焦点,这两个功能最重要的用途是提高Web应用一个极大的进步,无障碍web应用的一个主要标志就是恰当的焦点管理。

3、HTMLDocument的变化

3_1、readyState属性:判断文档加载的状态,两个可能值(loading,complete),下例:

if(document.readyState == 'complete'){
  //执行someThing
}

3_2、兼容模式

渲染页面的模式分为标准的和混杂的,区分模式需用到如下属性:

document.compatMode:标准模式下为'CSS1Compat',混杂模式下为'BackCompat'

4、字符集属性

document.charset:表示文档当前使用的字符集,可修改

document.defaultCharset:当前文档默认字符集

5、自定义数据属性

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

<div id='myDiv' data-appId='11111' data-name='Jack'></div>

添加属性后,可通过元素的dataset属性来访问自定义属性的值,不过会去掉data-前缀,如下例:

let div = document.getElementById("myDiv");

console.log(div.dataset.appId);//11111
console.log(div.dataset.name);//Jack

div.dataset.appId = 22222;
div.dataset.name = "Tom";

6、插入标记

6_1、innerHtml属性

在读模式下,返回调用元素的所有子节点(包括元素、注释和文本节点)对应的标记

在写模式下,会根据制定的值创建新的DOM树,然后用这个树替换调用元素原先的所有子节点

使用 innerHTML 属性也有一些限制。比如,在大多数浏览器中,通过 innerHTML 插入<script>元素并不会执行其中的脚本IE8 及更早版本是唯一能在这种情况下执行脚本的浏览器,但必须满足一些条件。一是必须为<script>元素指定 defer 属性,二是<script>元素必须位于(微软所谓的)“有作用域的元素”( scoped element)之后。 <script>元素被认为是“无作用域的元素”( NoScope element),也就是在页面中看不到的元素,与<style>元素或注释类似。如果想插入这段脚本,必须在前面添加个“有作用域的元素”,可以是一个文本节点,也可以是一个没有结束标签的元素如<input>。例如,下面这几行代码都可以正常执行:

div.innerHTML = "_<script defer>alert('hi');<\/script>";
div.innerHTML = "<div>&nbsp;</div><script defer>alert('hi');<\/script>";
div.innerHTML = "<input type=\"hidden\"><script defer>alert('hi');<\/script>";

但在 IE8 及更早版本中, <style>也是一个“没有作用域的元素”,因此必须像下面这样给它前置一个“有作用域的元素”:
div.innerHTML = "_<style type=\"text/css\">body {background-color: red; }</style>";
div.removeChild(div.firstChild);
并不是所有元素都支持 innerHTML 属性。不支持 innerHTML 的元素有: <col>、 <colgroup>、<frameset>、 <head>、 <html>、 <style>、 <table>、 <tbody>、 <thead>、 <tfoot>和<tr>。此外,在 IE8 及更早版本中, <title>元素也没有 innerHTML 属性。

6_2、outerHtml属性

在读模式下, outerHTML 返回调用它的元素及所有子节点的 HTML 标签。

在写模式下, outerHTML会根据指定的 HTML 字符串创建新的 DOM 子树,然后用这个 DOM 子树完全替换调用元素。下面是一个例子:

//使用 outerHTML 属性以下面这种方式设置值:
div.outerHTML = "<p>This is a paragraph.</p>";
//这行代码完成的操作与下面这些 DOM 脚本代码一样:
var p = document.createElement("p");
p.appendChild(document.createTextNode("This is a paragraph."));
div.parentNode.replaceChild(p, div);
//结果,就是新创建的<p>元素会取代 DOM 树中的<div>元素。

6_3、insertAdjacentHTML()方法

插入标记的最后一个新增方式是 insertAdjacentHTML()方法。这个方法最早也是在IE中出现的,它接收两个参数:插入位置和要插入的 HTML 文本。第一个参数必须是下列值之一:
 "beforebegin",在当前元素之前插入一个紧邻的同辈元素;
 "afterbegin", 在当前元素之下插入一个新的子元素或在第一个子元素之前再插入新的子元素;
 "beforeend", 在当前元素之下插入一个新的子元素或在最后一个子元素之后再插入新的子元素;
 "afterend",在当前元素之后插入一个紧邻的同辈元素。
注意,这些值都必须是小写形式。第二个参数是一个 HTML 字符串(与 innerHTML 和 outerHTML的值相同),如果浏览器无法解析该字符串,就会抛出错误。以下是这个方法的基本用法示例。

//作为前一个同辈元素插入
element.insertAdjacentHTML("beforebegin", "<p>Hello world!</p>");
//作为第一个子元素插入
element.insertAdjacentHTML("afterbegin", "<p>Hello world!</p>");
//作为最后一个子元素插入
element.insertAdjacentHTML("beforeend", "<p>Hello world!</p>");
//作为后一个同辈元素插入
element.insertAdjacentHTML("afterend", "<p>Hello world!</p>")

6_4、内存和性能问题

使用本节介绍的方法替换子节点可能会导致浏览器的内存占用问题,尤其是在 IE 中,问题更加明显。在删除带有事件处理程序或引用了其他 JavaScript 对象子树时,就有可能导致内存占用问题。假设某个元素有一个事件处理程序(或者引用了一个 JavaScript 对象作为属性),在使用前述某个属性将该元素从文档树中删除后,元素与事件处理程序(或 JavaScript 对象)之间的绑定关系在内存中并没有一并删除。如果这种情况频繁出现,页面占用的内存数量就会明显增加。因此,在使用 innerHTML、outerHTML 属性和 insertAdjacentHTML()方法时,最好先手工删除要被替换的元素的所有事件处理程序和 JavaScript 对象属性(第 13 章将进一步讨论事件处理程序)。

不过,使用这几个属性——特别是使用 innerHTML,仍然还是可以为我们提供很多便利的。一般来说,在插入大量新 HTML 标记时,使用 innerHTML 属性与通过多次 DOM 操作先创建节点再指定它们之间的关系相比,效率要高得多。这是因为在设置 innerHTML 或 outerHTML 时,就会创建一个 HTML解析器。这个解析器是在浏览器级别的代码(通常是 C++编写的)基础上运行的,因此比执行 JavaScript快得多。不可避免地,创建和销毁 HTML 解析器也会带来性能损失,所以最好能够将设置 innerHTML或 outerHTML 的次数控制在合理的范围内。

for (var i=0, len=values.length; i < len; i++){
  ul.innerHTML += "<li>" + values[i] + "</li>"; //每次循环先读取,后写入,也就是说进行了两次操作,要避免这种频繁操作!!
}

var itemsHtml = "";
for (var i=0, len=values.length; i < len; i++){
itemsHtml += "<li>" + values[i] + "</li>";
}
ul.innerHTML = itemsHtml;//这个例子的效率要高得多,因为它只对 innerHTML 执行了一次赋值操作

7、scrollIntoView()方法

scrollIntoView()可以在所有 HTML 元素上调用,通过滚动浏览器窗口或某个容器元素,调用元素就可以出现在视口中。如果给这个方法传入 true 作为参数,或者不传入任何参数,那么窗口滚动之后会让调用元素的顶部与视口顶部尽可能平齐。如果传入 false 作为参数,调用元素会尽可能全部出现在视口中,(可能的话,调用元素的底部会与视口顶部平齐。)不过顶部不一定平齐,例如:

//让元素可见
document.forms[0].scrollIntoView();

当页面发生变化时,一般会用这个方法来吸引用户的注意力。实际上,为某个元素设置焦点也会导致浏览器滚动并显示出获得焦点的元素。
支持 scrollIntoView()方法的浏览器有 IE、 Firefox、 Safari 和 Opera。

2、专有扩展

1、文档说明

要强制浏览器以某种模式渲染页面,可以使用 HTTP 头部信息 X-UA-Compatible,或通过等价的<meta>标签来设置:
<meta http-equiv="X-UA-Compatible" content="IE=IEVersion">
注意,这里 IE 的版本( IEVersion)有以下一些不同的值。
 Edge:始终以最新的文档模式来渲染页面。忽略文档类型声明。对于 IE8,始终保持以 IE8 标
准模式渲染页面。对于 IE9,则以 IE9 标准模式渲染页面。
 EmulateIE9:如果有文档类型声明,则以 IE9 标准模式渲染页面,否则将文档模式设置为 IE5。
 EmulateIE8:如果有文档类型声明,则以 IE8 标准模式渲染页面,否则将文档模式设置为 IE5。
 EmulateIE7:如果有文档类型声明,则以 IE7 标准模式渲染页面,否则将文档模式设置为 IE5。
 9:强制以 IE9 标准模式渲染页面,忽略文档类型声明。
 8:强制以 IE8 标准模式渲染页面,忽略文档类型声明。
 7:强制以 IE7 标准模式渲染页面,忽略文档类型声明。
 5:强制将文档模式设置为 IE5,忽略文档类型声明。
比如,要想让文档模式像在 IE7 中一样,可以使用下面这行代码:

<meta http-equiv="X-UA-Compatible" content="IE=EmulateIE7">

如果不打算考虑文档类型声明,而直接使用 IE7 标准模式,那么可以使用下面这行代码:

<meta http-equiv="X-UA-Compatible" content="IE=7">

2、children属性

由于 IE9 之前的版本与其他浏览器在处理文本节点中的空白符时有差异,因此就出现了 children属性。这个属性是 HTMLCollection 的实例,只包含元素中同样还是元素的子节点。除此之外,children 属性与 childNodes 没有什么区别,即在元素只包含元素子节点时,这两个属性的值相同。下面是访问 children 属性的示例代码:
var childCount = element.children.length;
var firstChild = element.children[0];
支持 children 属性的浏览器有 IE5、 Firefox 3.5、 Safari 2(但有 bug)、 Safari 3(完全支持)、 Opera8和 Chrome(所有版本)。 IE8 及更早版本的 children 属性中也会包含注释节点,但 IE9 之后的版本则只返回元素节点。

3、contains()方法

调用 contains()方法的应该是祖先节点,也就是搜索开始的节点,这个方法接收一个参数,即要检测的后代节点。如果被检测的节点是后代节点,该方法返回 true;否则,返回 false。以下是一个例子:

alert(document.documentElement.contains(document.body)); //true

使用 DOM Level 3 compareDocumentPosition()也能够确定节点间的关系。支持这个方法的浏览器有 IE9+、 Firefox、 Safari、 Opera 9.5+和 Chrome。如前所述,这个方法用于确定两个节点间的关系,返回一个表示该关系的位掩码( bitmask)。下表列出了这个位掩码的值。

使用一些浏览器及能力检测,就可以写出如下所示的一个通用的 contains 函数:

function contains(refNode, otherNode){
  //首先检测 refNode 中是否存在 contains()方法(能力检测)
  if (typeof refNode.contains == "function" && (!client.engine.webkit || client.engine.webkit >= 522)){
    return refNode.contains(otherNode);
  } 
  //检查是否存在 compareDocumentPosition()方法
  else if (typeof refNode.compareDocumentPosition == "function"){
    return !!(refNode.compareDocumentPosition(otherNode) & 16);
  } 
  //自 otherNode开始向上遍历 DOM 结构,以递归方式取得 parentNode,并检查其是否与 refNode 相等
  else {
    var node = otherNode.parentNode;
    do {
      if (node === refNode) return true;
      else node = node.parentNode;
    } while (node !== null);
    return false;
  }
}

4、插入文本

4_1、innerText

在通过innerText 读取值时,它会按照由浅入深的顺序,将子文档树中的所有文本拼接起来。

在通过innerText 写入值时,结果会删除元素的所有子节点,插入包含相应文本值的文本节点

4_2、outerText

除了作用范围扩大到了包含调用它的节点之外, outerText 与 innerText 基本上没有多大区别。在读取文本值时, outerText 与 innerText 的结果完全一样。但在写模式下, outerText 就完全不同了: outerText 不只是替换调用它的元素的子节点,而是会替换整个元素(包括子节点)。比如:

div.outerText = "Hello world!";
//这行代码实际上相当于如下两行代码:
var text = document.createTextNode("Hello world!");
div.parentNode.replaceChild(text, div);

本质上,新的文本节点会完全取代调用 outerText 的元素。此后,该元素就从文档中被删除,无法访问。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值