在所有现代浏览器中,通过 innerHTML 插入的<script>标签是不会执行的。而在 IE8 及之前的版 本中,只要这样插入的<script>元素指定了 defer 属性,且<script>之前是“受控元素”(scoped element),那就是可以执行的。<script>元素与<style>或注释一样,都是“非受控元素”(NoScope element),也就是在页面上看不到它们。IE 会把 innerHTML 中从非受控元素开始的内容都删掉,也就 是说下面的例子是行不通的:
```js
// 以下都可行
div.innerHTML = "_<script defer>console.log('hi');<\/script>";
div.innerHTML = "<div> </div><script defer>console.log('hi');<\/script>"; div.innerHTML = "<input type=\"hidden\"><script defer>console. log('hi');<\/script>";
```
第一行会在<script>元素前面插入一个文本节点。为了不影响页面排版,可能稍后需要删掉这个 文本节点。第二行与之类似,使用了包含空格的<div>元素。空<div>是不行的,必须包含一点内容, 以强制创建一个文本节点。同样,这个<div>元素可能也需要事后删除,以免影响页面外观。第三行使 用了一个隐藏的<input>字段来达成同样的目的。因为这个字段不影响页面布局,所以应该是最理想的 方案。
在 IE 中,通过 innerHTML 插入<style>也会有类似的问题。多数浏览器支持使用 innerHTML 插 入<style>元素:
```js
div.innerHTML = "<style type=\"text/css\">body {background-color: red; }</style>"; 但在 IE8 及之前的版本中,<style>也被认为是非受控元素,所以必须前置一个受控元素:
```
```js
div.innerHTML = "_<style type=\"text/css\">body {background-color: red; }</style>";
div.removeChild(div.firstChild);
```
## 3. outerHTML 属性
读取 outerHTML 属性时,会返回调用它的元素(及所有后代元素)的 HTML 字符串。在写入 outerHTML 属性时,调用它的元素会被传入的 HTML 字符串经解释之后生成的 DOM 子树取代。比如 下面的 HTML 代码:
```js
<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>
```
在这个<div>元素上调用 outerHTML 会返回相同的字符串,包括<div>本身。注意,浏览器因解 析和解释 HTML 代码的机制不同,返回的字符串也可能不同。(跟 innerHTML 的情况是一样的。)
如果使用 outerHTML 设置 HTML,比如:
```js
div.outerHTML = "<p>This is a paragraph.</p>";
```
则会得到与执行以下脚本相同的结果:
```js
let p = document.createElement("p"); p.appendChild(document.createTextNode("This is a paragraph.")); div.parentNode.replaceChild(p, div);
```
新的<p>元素会取代 DOM 树中原来的<div>元素。
## 4. insertAdjacentHTML()与 insertAdjacentText()
关于插入标签的最后两个新增方法是 insertAdjacentHTML()和 insertAdjacentText()。这两 个方法最早源自 IE,它们都接收两个参数:要插入标记的位置和要插入的 HTML 或文本。第一个参数 必须是下列值中的一个:
"beforebegin",插入当前元素前面,作为前一个同胞节点;
"afterbegin",插入当前元素内部,作为新的子节点或放在第一个子节点前面;
"beforeend",插入当前元素内部,作为新的子节点或放在最后一个子节点后面;
"afterend",插入当前元素后面,作为下一个同胞节点。 注意这几个值是不区分大小写的。第二个参数会作为 HTML 字符串解析(与 innerHTML 和
outerHTML 相同)或者作为纯文本解析(与 innerText 和 outerText 相同)。如果是 HTML,则会 在解析出错时抛出错误。下面展示了基本用法1 假设当前元素是<p>Hello world!</p>,则"beforebegin"和"afterbegin"中的"begin"指开始标签<p>;而 "afterend"和"beforeend"中的"end"指结束标签</p>。
注意 Firefox在内容类型为application/xhtml+xml的XHTML文档中对innerHTML 更加严格。在 XHTML 文档中使用 innerHTML,必须使用格式良好的 XHTML 代码。否 则,在 Firefox 中会静默失败。
```js
// 作为前一个同胞节点插入
element.insertAdjacentHTML("beforebegin", "<p>Hello world!</p>"); element.insertAdjacentText("beforebegin", "Hello world!");
// 作为第一个子节点插入
element.insertAdjacentHTML("afterbegin", "<p>Hello world!</p>"); element.insertAdjacentText("afterbegin", "Hello world!");
// 作为最后一个子节点插入
element.insertAdjacentHTML("beforeend", "<p>Hello world!</p>"); element.insertAdjacentText("beforeend", "Hello world!");
// 作为下一个同胞节点插入
element.insertAdjacentHTML("afterend", "<p>Hello world!</p>"); element. insertAdjacentText("afterend", "Hello world!");
```