本文承接《DOM扩展:DOM API的进一步增强[总结篇-上],继续总结DOM扩展相关的功能和API。
3.6 插入标记
DOM1级中的接口已经提供了向文档中插入内容的接口,但是在给文档插入大量HTML标记的时候操作还是很繁杂的,每次插入一个元素,不仅要调用创建元素和文本节点的接口,还要调用appendChild等向文档中添加元素的接口,而且在添加时还要按照正确的顺序。而如果使用插入标记的方法,直接向文档中插入HTML字符串,由执行环境自动解析HTML字符串并创建相应的节点并添加到文档中,这样的话操作就方便多了。与插入标记相关的DOM扩展总结如下:
 
3.6.1 innerHTML属性
使用innerHTML可以读取元素所有子节点对应的HTML字符串(包括元素、注释节点和文本);也可以为元素设置子节点的HTML标记,此时会根据指定的值创建新的DOM树,然后用新的DOM树替换元素的子节点。
 
(1)读取innerHTML属性
以下面的代码为例:
<div id="wrapper">
<p>一个段落在这里</p>
<span>这里是一个span</span>
</div> 我们如果获取div#wrapper的innerHTML值应该就是:
<p>一个段落在这里</p>
<span>这里是一个span</span>

但是IE8及以下的浏览器,在使用innerHTML属性时返回的字符串有两处不同:

[1]所有的标签都会转为大写
[2]所有的空白节点都会被去掉
仍以上面的代码为了,在IE8及以下的浏览器中返回的内容就是:
<P>一个段落在这里</P><SPAN>这里是一个span</SPAN>
(2)设置innerHTML属性
设置innerHTML属性时,HTML字符串会被解析为DOM树并替换元素的所有子节点。如果传入的字符串不包含任何标签,那么生成的就是文本节点,而如果传入的字符串包含由HTML标签,那么标签就会被解析为相应的HTML元素,这一点与创建Text类型节点时的情况是大不相同的:
我们还是以上面的div#wrapper为例:
如果调用:
div.innerHTML = "<strong>\"This is innerHTML\"</strong>";
则<strong>会被正确地解析,其中的文本就会被渲染成粗体。
 
使用innerHTML也存在一些限制:
[1]script标签
在大部分浏览器中,通过innerHTML插入的<script>标签不会被执行,只有IE9及以下的浏览器会执行,但也需要满足一定的条件,首先需要为script添加defer特性,其次<script>标签必须位于"有作用域"的元素之后("有作用域"的元素这里可以理解为会直观显示在页面上的元素,比如script,style这些元素是不会显示在页面上的,而input、div等元素会直接显示在页面上,因此可以称为"有作用域")。还是以上面的div#wrapper为例,有如下代码:
div.innerHTML = "<script>alert('dd')<\/script>";

代码执行后,标签会被插入div中,但脚本在任何浏览器中都不会执行。再来修改一下代码:

div.innerHTML = "<script defer='defer'>alert('dd')<\/script>";

这段代码为innerHTML加入了一个defer特性,但正如上文所讲的,script是一个"没有作用域"的元素,所以在IE9及以下浏览器中,脚本还是不会被执行。这个时候只要在<script>前面添加一个字符串或者其他"有作用域"的元素即可,为了不影响文档的实际内容,一般在script标签之前添加一个隐藏的input元素即可,代码如下:

div.innerHTML = "<input type='hidden'/><script defer='defer'>alert('dd')<\/script>";

这样在IE9及以下的浏览器中,脚本就能够执行了。

注:如果是引入外部javascript文件,那么所有浏览器都不会下载执行js文件和其中的代码
[2]style和link标签
在IE8及以下的浏览器中,如果插入style标签,必须也要跟随在一个"有作用域"的元素之后,因此可以采用<script>一节中介绍的方法。高版本IE及其他浏览器中插入的style样式都可以被执行。
另外,如果使用link标签引入外部样式,那么和style标签的效果是一样的
 
还有一些元素是不支持innerHTML属性的,包括:<table>、 <thead>、 <tbody>、 <tfoot>、 <tr>、 <style>、 <html>、 <head>、 <frameset>、<col>、<colgroup>
由于innerHTML可以插入HTML标签,那么就涉及到安全问题,最典型的的就是XSS,因此在使用innerHTML时应该对插入的字符串进行安全处理,特别是需要保存到数据库中的字符串代码。比如插入的字符串不应该包含脚本代码(及时在一些浏览器中脚本代码不会执行),不应该包含事件处理程序和外部链接等。IE8中提供了window.toStaticHTML(),可以将传入的字符串进行处理:删除脚本节点和事件处理程序。
 
3.6.2 outerHTML属性
从字面上

,outerHTML与innerHTML的不同就在于"outer",也就是说,outerHTML属性在读取或写入时除了包含所有子节点,同时也把自己算进去了。我们还是以3.6.1中的div#wrapper为例,读取outerHTML时返回的是:
<div id="wrapper">
<p>一个段落在这里</p>
<span>这里是一个span</span>
</div>

在IE8及以下的浏览器返回:

<DIV id=wrapper><P>一个段落在这里</P><SPAN>这里是一个span</SPAN></DIV>

而如果是写入outerHTML属性的话,则会将div本身直接替换掉,这也是与innerHTML的不同之处。

 
3.6.3 insertAdjacentHTML方法
insertAdjacentHTML方法为元素提供了更加灵活的标记插入方法,它接收两个参数:插入的位置和HTML字符串,其中插入的位置必须是下面几个参数:
"beforebegin":在元素之前插入一个紧邻的同辈元素
"afterbegin":如果元素没有子元素,那么就直接插入;如果元素有子元素,就在第一个子元素之前插入
"beforeend":如果元素没有子元素,那么就直接插入;如果元素有子元素,就在最后一个子元素之后插入
"afterend":在元素之后插入一个紧邻的同辈元素
我们仍以3.6.1中的div为例,调用如下代码:
div.insertAdjacentHTML("beforeend","<p>在结束前插入一个</p>");
console.log(div.innerHTML);

则返回的代码就是:


<p>一个段落在这里</p>
<span>这里是一个span</span>
<p>在结束前插入一个</p>

insertAdjacentHTML方法的兼容性如下图:


在IE6-8下,table, tbody, thead,  tr 元素调用这个方法会报错。

3.6 scrollIntoView()方法

DOM1级中的接口已经scrollIntoView方法可以在所有的HTML元素上调用,调用这个方法后,浏览器会通过滚动窗口或者某个容器窗口来让元素出现在视口中。
这个方法接收一个布尔型参数,默认为true,如果为true的话,滚动后浏览器会让视口顶部与元素顶部尽可能平齐;如果为false,调用元素会尽可能出现在视口中。
 
4

专有扩展
 
不同的浏览器开发商可能会为DOM扩展不同的功能,这些功能有的被吸收进入了标准,正如第3章中所介绍的这些扩展,而有的功能却还没有被纳入标准中,不过这并不代表着这些功能以后也不会被写入标准中,只是目前这些功能还是各浏览器专有的扩展,只能在特定的浏览器中使用。
4.1 文档模式
IE8中引入了文档模式的概念,文档模式决定了我们可以使用哪些功能,也就是说,文档模式决定了我们可以使用哪个级别的CSS,可以使用JavaScript API中的哪些功能以及如何对待文档类型。之后的IE版本都提供了向下兼容的文档模式,比如在IE9中,可选的文档模式有:IE5(以混杂模式渲染页面)、IE7(以IE7的标准模式渲染页面)、IE8(以IE8的标准模式渲染页面,到了IE8,DOM Selectors API、CSS2.1的完整功能以部分CSS3的功能就都可以使用了)、IE9(以IE9的标准模式渲染页面,到了IE9,ES5、CSS3以及更多的HTML5的功能也都可以使用了)

要强制浏览器以某种模式渲染页面,可以通过设置HTTP的X-UA-Compatible头部或设置对应的meta标签来实现,声明方式为:

<meta http-equiv="x-ua-compatible" content="IE=IEVersion"/>

其中,IEVersion的可能取值有:

[1]edge:始终以最新的文档模式来渲染页面,忽略文档类型声明
[2]EmulateIEXX:XX代表某个IE版本,即如果有文档类型声明,那么就以XX版本的IE标准模式来渲染页面,否则把文档模式设为IE5
[3]XX:XX代表某个IE版本,即忽略文档类型声明,以XX版本的IE标准模式渲染页面
如果没有设置X-UA-Compatible,则浏览器会根据文档类型声明选择最佳的文档模式进行渲染。
document.documentMode可以判断文档当前所处的文档模式,这个属性只有IE支持。
4.2 children属性
IE8及以下的浏览器在处理文本节点的空白节点时与其他浏览器有所不同,因此使用childNodes属性遍历DOM树时还需要判断某个子节点的具体类型,而children属性的出现可以解决这个问题,它只返回一个元素所有的子元素。
注:IE8及以下的浏览器也会返回注释节点。
IE5+,Firefox3.5+,chrome,Opera8+,Safari3+支持children属性。

4.3 contains方法
实际开发中,经常需要判断一个节点是否包含另一个节点,比如我们有如下HTML代码:
<body>
<div id="div-1">
<div id="title">
<h1 id="title-h1">标题</h1>
<span id="more">更多</span>
</div>
</div>
<div id="div-2">
<div id="content-wrapper">
<div id="block">
<p id="desc">这里是一段描述</p>
<img id="img" src=""/>
</div>
</div>
</div>
</body>

  

如果我们想要判断div#div-2是否包含span#more,如果只借助DOM1级的API,那么我们会可能写出如下代码:
var div2 = document.getElementById("div-2"),
div1 = document.getElementById("div-1"),
more = document.getElementById("more");
alert(nodeContains(div1, more));
alert(nodeContains(div2, more));
function nodeContains(node, childNode){
var result = false;
while(childNode != null){
if(childNode === node){
result = true;
break;
}
childNode = childNode.parentNode;
}
return result;
}

代码执行后将分别弹出true和false

注:Firefox9+和其他浏览器都支持contains方法。

有了contains方法之后,我们可以直接使用:
alert(div1.contains(more));
alert(div2.contains(more));
也将分别弹出true和false。
另外,DOM3级中又定义了compareDocumentPosition方法,也可以用来判断一个节点是否包含另一个节点,这里我们不再详解这个方法,可以参考:

4.4 插入文本

3.6节介绍了插入标记相关的属性:innerHTML和outerHTML,并且这两个特性已经被纳入了HTML5标准之中,而另外两个插入文本相关的属性则没有被标准看上,它们就是innerText和outerText。
4.4.1 innerText属性
使用innerText属性可以读取元素内的文本内容,也可以设置元素的文本内容,
(1)读取innerText属性
如果调用Element.innerText属性,会按照由浅到深的顺序,将元素的所有文本节点拼接起来并返回。但是由于不同的浏览器处理空白符的方式不同,因此返回的字符串也可能不包含原始HTML代码中的缩进。有如下代码:
<div id="wrapper">
<p>一个段落在这里</p>
<span>这里是一个span</span>
</div>

那么调用div#wrapper的innerText属性返回的内容可能是:

一个段落在这里

这里是一个span

也可能是:

一个段落在这里
这里是一个span

这主要还是由于不同浏览器处理空白符节点的方式不同而导致的。

(2)设置innerText属性
如果为一个元素设置innerText属性,则意味着删除元素的所有子节点,并将文本节点插入,文本中包含的HTML语法字符都会被转义,还是以上面的div#wrapper为例:
div.innerText = "<strong>Hello</strong>";

代码执行后,显示结果为:

支持innerText属性的浏览器有:IE4+,chrome,Opera8+,Safari3+;特别注意的是:firefox不支持innerText,但是有一个类似的textContent属性,另外还支持textContent属性的有:IE9+,chrome,Opera10+,Safari3+
注:textContent和innerText返回的内容有时候是不相同,比如innerText会忽略元素内部所有的脚本标签代码和样式标签代码,但textContent却不会忽略。
4.4.2 outerText属性
与innerText属性相似,在读取时,返回的结果与innerText相同,在设置时,则会将整个节点直接替换掉。

DOM扩展:DOM API的进一步增强[总结篇-下]的更多相关文章

  1. DOM扩展:DOM API的进一步增强[总结篇-上]

    DOM1级主要定义了文档的底层结构,并提供了基本的查询操作的API,总体而言这些API已经比较完善,我们可以通过这些API完成大部分的DOM操作.然而,为了扩展DOM API的功能,同时进一步提高DO ...

  2. DOM扩展-Selectors API(选择符 API)、元素遍历

    DOM扩展 对DOM的两个主要扩展是SelectorsAPI(选择符API)和HTML5 SelectorsAPI(选择符API)是由W3C发起制定的一个标准,致力于浏览器原生支持CSS查询,Sele ...

  3. 前端开发工程师 - 03.DOM编程艺术 - 第1章.基础篇(下)

    第1章.基础篇(下) Abstract: 数据通信.数据存储.动画.音频与视频.canvas.BOM.表单操作.列表操作 数据通信(HTTP协议) HTTP事务: 客户端向服务器端发送HTTP请求报文 ...

  4. HTML5学习笔记(二十四):DOM扩展

    DOM扩展 DOM标准扩展最开始都是来自各个浏览器的自定义扩展DOM的功能,后被收录为标准的DOM相关API. 本笔记只记录被各大浏览器支持的标准扩展,对于特定浏览器的专有扩展不讨论. 选择符API ...

  5. dom扩展

    第十一章 DOM扩展 一.选择符API 1.querySelector()方法             接收一个CSS选择符,返回与该模式匹配的第一个元素,如果没有找到匹配的元素,返回null. 2. ...

  6. DOM扩展札记

    Selector API HTML5 DOM扩展 Element Traversal规范 Selector API 众多JavaScript库中,最常用的一个功能就是根据css选择符选择与某个模式匹配 ...

  7. 11. javacript高级程序设计-DOM扩展

    1. DOM扩展 1.1 选择符API l querySelector() 接收一个css选择符,返回与该模式匹配的第一个元素 l querySelectorAll() 接收一个css选择符,返回所有 ...

  8. 《JAVASCRIPT高级程序设计》DOM扩展

    虽然DOM为XML及HTML文档交互制定了一系列的API,但仍然有几个规范对标准的DOM进行了扩展.这些扩展中,有很多是浏览器专有的,但后来成了事实标准,于是其他浏览器也提供了相同的实现:浏览器开发商 ...

  9. JavaScript基础笔记(八)DOM扩展

    DOM扩展 一.选择符API Selectors API是由W3C发起制定的一个标准,致力于让浏览器原生支持CSS查询. 一)querySelector() 在Document和Element类型实例 ...

随机推荐

  1. 2017/2/16:自己ajax+json习惯性写法 代码拼接的写法 +json用post提交乱码的原因

    1.先导入jquery的包 2.ajax的写法跟注意点 返回一个list的写法 代码拼接写法: html层: 2.script处 4:在你前面传递参数的时候没有遇到乱码问题的情况下,你使用json并且 ...

  2. 在myeclipse上发布自己的webservice

       什么是WebServices? 它是一种构建应用程序的普遍模型,可以在任何支持网络通信的操作系统中实施运行;它是一种新的web应用程序分支,是自包含.自描述.模块化的应用,可以发布.定位.通过w ...

  3. optimizer_switch引起的诡异问题

    参数描述 MySQL中不同的版本优化器会有很多新特性,比如MRR.BKA等,optimizer_switch这个参数就是控制查询优化器怎样使用这些特性.很多情况下我们会根据自身的需求去设置optimi ...

  4. De Bruijn序列

    最近文章中经常出现及De Bruijin 这个关键字,网上搜索了一下,记录下来. De Bruijn序列 (德布鲁因序列) 问题:能否构造一个长度为2的n次方的二进制环状串,使得二进制环状串中总共2的 ...

  5. 2018.11.17 bzoj4259: 残缺的字符串(fft)

    传送门 fftfftfft套路题. 我们把aaa ~ zzz映射成111 ~ 262626,然后把∗*∗映射成000. 考虑对于两个长度都为nnn的字符串A,BA,BA,B. 我们定义一个差异函数di ...

  6. 黑白二值图像周长测量--C#实现

    假设是单像素线白色用1(对应RGB(255,0,0))表示,背景用0(对应RBG(0,0,0))表示. 考虑3种类型的边界 水平方向  0->1  1->0   类似垂直方向也是0-> ...

  7. c++关键字volatile的作用

    1.易变性 1.1概念 编译器对volatile修饰的变量,当要读取这个变量时,任何情况下都会从内存中读取,而不会从寄存器缓存中读取(因为每次都从内存中读取体现出变量的“易变”) 1.2测试代码(VS ...

  8. SpringBoot2.0.2 不使用parent作为maven单继承方式操作 : org.springframework.boot : spring-boot-dependencies : 2.0.2.RELEASE

    1.pom配置方式 <?xml version="1.0" encoding="UTF-8"?> <project xmlns="h ...

  9. 研究生flag

    是时候定个计划了,感觉日子一天天水,不加油学点东西,迟早要掉队…… 刷刷算法题库吧,貌似选几个管用的刷刷——https://hihocoder.com/problemset 争取明年三月份的PAT顶级 ...

  10. 安卓开机logo和开机动画的几种实现方法

    安卓4.2可用方法2-4,第一种方法未验证. 从理论上来说,android 有4个开机启动画面. 第一个应该是U-BOOT的启动画面,有些设备为了满足按动电源即有显示,在UBOOT里加了开机画面,实现 ...