Jsdom: 你如何加载外部脚本?

创建于 2017-07-07  ·  3评论  ·  资料来源: jsdom/jsdom

jsdom 可以运行在文档的<head>标记内内联的脚本,但是如何让它运行通过<script src="">链接到文档头部的脚本?

对于我正在使用的选项:

{
    url: url,
    resources: 'usable',
    runScripts: 'dangerously',
}

基础信息:

  • Node.js 版本:8.1.2
  • jsdom 版本:11.1.0

最小复制案例:

// index.js
const request = require('request')
const jsdom = require('jsdom')
const {JSDOM} = jsdom
const url = 'http://localhost:8000'

request(url, (error, response, body) => {
  const options = {
    url: url,
    resources: 'usable',
    runScripts: 'dangerously',
  }

  const dom = new JSDOM(body, options)

  console.log(dom.window.document.body.children.length) // Expecting to see `1`
  console.log(dom.window.document.body.innerHTML) // Expecting to see `<h1>Hello world</h1>`
})
// external.js
document.addEventListener('DOMContentLoaded', () => {
  document.write('<h1>Hello world!</h1>')
})
<!-- index.html -->
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>JSDOM test</title>
    <script src="external.js"></script>
  </head>
  <body>
  </body>
</html>

完整的最小工作示例: https ://github.com/cg433n/jsdom-test

最有用的评论

这里的问题是DOMContentLoaded是一个异步事件。 你在它有机会发生之前就登录了。 您需要等待它触发; 只有这样你的document.write()才会发生。

像这样的东西应该可以工作:

const dom = new JSDOM(body, options)

dom.window.document.addEventListener('DOMContentLoaded', () => {
  // We need to delay one extra turn because we are the first DOMContentLoaded listener,
  // but we want to execute this code only after the second DOMContentLoaded listener
  // (added by external.js) fires.
  setImmediate(() => {
    console.log(dom.window.document.body.children.length) // Expecting to see `1`
    console.log(dom.window.document.body.innerHTML) // Expecting to see `<h1>Hello world</h1>`
  });
});

所有3条评论

这里的问题是DOMContentLoaded是一个异步事件。 你在它有机会发生之前就登录了。 您需要等待它触发; 只有这样你的document.write()才会发生。

像这样的东西应该可以工作:

const dom = new JSDOM(body, options)

dom.window.document.addEventListener('DOMContentLoaded', () => {
  // We need to delay one extra turn because we are the first DOMContentLoaded listener,
  // but we want to execute this code only after the second DOMContentLoaded listener
  // (added by external.js) fires.
  setImmediate(() => {
    console.log(dom.window.document.body.children.length) // Expecting to see `1`
    console.log(dom.window.document.body.innerHTML) // Expecting to see `<h1>Hello world</h1>`
  });
});

我懂了! 你们太棒了——继续努力!

注意:上述演示的 2 个功能存在风险。

FS 黑客

或者,我建议使用fs从文件中读取和加载 js 代码,请参阅Stackoverflow基于 #3023 中的@EricRicketts ' FS.read()方法和@Domenic中的addEventListener() #1914. 我建议的工作演示包括:

  • 使用fs.readFileSync将外部 js 作为字符串加载到 html 中
  • 循环处理几个外部js文件
  • 触发外部 js 函数的用例
  • 将终端变量传递给节点,然后传递给外部 js 函数的用例

这可能会阻止您进行 xhr / API 调用,因此只能部分解决问题。

网址

我无法弄清楚获取网址的方法。
理想情况下,通过 url 工作演示加载 external.js 文件的更新的最小 JSDOM将受到欢迎。 :心:

此页面是否有帮助?
0 / 5 - 0 等级