Skip to content

DOM 操作技术

动态脚本

动态脚本:在页面加载时不存在,但将来的某一时刻通过修改 DOM 动态添加的脚本。

创建动态脚本有两种方式:插入外部脚本和插入内联 JS 代码。

插入外部脚本

以下面这个 <script> 元素为例子:

html
<script src="example.js"></script>

动态插入该脚本的代码如下:

ts
export function loadScript(src: string) {
  const script = document.createElement('script')
  script.src = src
  document.body.appendChild(script)
}
ts
loadScript('example.js')

INFO

<script> 添加到文档之后才会开始加载外部脚本文件,加载完成后会立即执行。

默认情况下,动态脚本的行为是异步的。

  • 它们不会阻塞任何东西;
  • 先加载完的先执行。

但是可以通过设置 script.async = false 改变这个规则。设置该值后,脚本将按照在文档中的顺序执行,类似于设置 defer

如果设置了 script.async = false,在加载一个库和一个依赖于它的脚本时,添加顺序就很重要。

插入内联 JS 代码

ts
export function loadInlineScript(code: string) {
  const script = document.createElement('script')
  try {
    script.appendChild(document.createTextNode(code))
  } catch (e) {
    // 上面的代码在 IE 中会报错,IE 将 <script> 视为一个特殊元素,不允许 DOM
    // 访问其子节点。不过我们可以通过 text 属性来插入代码。
    script.text = code
  }
  document.body.appendChild(script)
}
ts
loadInlineScript("function hi() { alert('hi'); }")

INFO

以这种方式加载的代码运行在全局作用域。实际上,这种方式与在全局作用域中使用 eval() 是一样的。

动态样式

动态样式:在页面加载时不存在,但将来的某一时刻通过修改 DOM 动态添加的样式。

创建动态样式有两种方式:使用 <link> 插入外部样式和使用 <style> 插入内嵌样式。

插入外部样式

以下面这个 <link> 元素为例子:

html
<link rel="stylesheet" href="example.css" />

动态插入该样式的代码如下:

ts
export function loadCSS(src: string) {
  const link = document.createElement('link')
  link.rel = 'stylesheet'
  link.href = src
  // 必须将 <link> 添加到 <head> 中,才能保证在所有浏览器中的行为一致。
  document.head.appendChild(link)
}
ts
loadCSS('example.css')

INFO

<link> 添加到文档之后才会开始加载外部样式,这个过程也是异步的。

插入内嵌样式

ts
export function loadStyle(styles: string) {
  const style = document.createElement('style')
  try {
    style.appendChild(document.createTextNode(styles))
  } catch (e) {
    // 与动态脚本类似,需要针对 IE 做特殊处理。
    if (style.styleSheet) {
      style.styleSheet.cssText = styles
    }
  }
  document.head.appendChild(style)
}
ts
loadStyle('body{background-color:red;}')

DANGER

如果针对 IE 编写代码,请务必小心使用 styleSheet.cssText 属性。在重用同一个 <style> 并再次设置这个属性时,有可能会导致浏览器崩溃。同样,设置 cssText 为空字符串也可能导致浏览器崩溃。

References

  • JavaScript 高级程序设计(第 3 版)第 10 章第 2 节
  • 动态脚本