document.createElement 不加载到 DOM 中

Ric*_*een 1 javascript jquery-selectors createelement ecmascript-6

有没有一种方法可以在不运行代码的情况下创建可解析的Dom?我会解释未来;

我收到一大堆 CK 编辑器创建的 HTML 代码,但想从中解析元素以创建指定的视图。例如,我想将第一段作为介绍,将第一张图像作为主图像。另外,我想检索所有图像以创建画廊。

为此,我创建了一个简单但有效的函数:

export const getFromContent = (html, qsa) => {
    const elm = document.createElement("DIV");
    elm.innerHTML = html;
    let r = elm.querySelectorAll(qsa);
    return r;
}
Run Code Online (Sandbox Code Playgroud)

这项工作几乎完美 - 唯一的问题是将所有内容添加到 DOM(我使用这个术语正确吗?),这意味着所有资源都会被加载,即使它没有显示在页面上。

在我的示例中,我想在显示之前通过 //res.cloudinary.com/ com 压缩图像加载所有图像,但由于所有图像都已加载,因此没有必要。

有没有办法只用基本的 JS 来保留这个好的“版本”?

PS:我知道我可以使用正则表达式将所有“src”重写为“presrc”,但我真的很想在不更改代码的情况下执行此操作,从而为错误创造空间。

最好的问候理查德

T.J*_*der 6

\n

这项工作几乎完美 - 唯一的问题是将所有内容添加到 DOM 中......

\n
\n

它创建 DOM 元素(这就是您这样做的原因!),但它不会将它们添加到窗口的文档中。但请注意,这样做可能会运行 HTML 中的代码(详细信息如下)。这样做:

\n
    \n
  • 不会将或其内容放在div文档中的任何位置。
  • \n
  • 不会link加载HTML 中的标签定义的任何样式表。
  • \n
  • 不会获取 HTML 中标记引用的任何脚本文件script src="xyz"(因此不会运行代码)。
  • \n
  • 不会script运行HTML 中内联标记中的任何代码。
  • \n
  • onXyz添加通过HTML 中元素的属性定义的事件处理程序
  • \n
  • 加载 HTML 中定义的任何图像。
  • \n
\n

最后两点的组合意味着它可以运行任意代码,如下所示:

\n

\r\n
\r\n
const getFromContent = (html, qsa) => {\n    const elm = document.createElement("DIV");\n    elm.innerHTML = html;\n    let r = elm.querySelectorAll(qsa);\n    return r;\n};\n\ngetFromContent(\n    `<img\n        src="http://example.com/alksdjflsadkf"\n        onload="console.log(\'Arbitrary code ran!\');"\n        onerror="console.log(\'Arbitrary code ran!\');"\n    >`,\n    "p"\n);
Run Code Online (Sandbox Code Playgroud)\r\n
\r\n
\r\n

\n

如果您稍后将其添加div到文档中,则会加载由linkHTML 中的标记定义的任何样式表,但不会运行script元素中的代码(无论是内联还是通过 引用src)。

\n

也就是说,您可能想考虑使用DOMParser

\n
export const getFromContent = (html, selector) => {\n    const parser = new DOMParser();\n    const dom = parser.parseFromString(html, "text/html");\n    let r = dom.querySelectorAll(selector);\n    return r;\n};\n
Run Code Online (Sandbox Code Playgroud)\n

它甚至不会加载 HTML 中定义的图像,尽管它添加了通过内联onXyz属性定义的处理程序,但它不会触发任何事件,因此这些处理程序不会运行\xc2\xa0\xe2\x80\ x94 直到或除非您将生成的文档的内容添加到活动文档中。它只是解析树并返回一个文档。

\n

实例:

\n

\r\n
\r\n
export const getFromContent = (html, selector) => {\n    const parser = new DOMParser();\n    const dom = parser.parseFromString(html, "text/html");\n    let r = dom.querySelectorAll(selector);\n    return r;\n};\n
Run Code Online (Sandbox Code Playgroud)\r\n
\r\n
\r\n

\n

请注意,img\ 的内联处理程序从未被触发。如果您将元素(或其祖先)添加到活动文档中,则会出现以下情况:img

\n
\n

注意:当接受用户输入并将其呈现为 HTML 时,在使用该输入之前对其进行清理以删除不需要的内容通常很重要。例如,我提到script元素不会被评估,这是事实,但如果内容包含<img src="javascript:doSomethingNefarious()">在其中,并且您将该图像附加到文档(直接或间接),则该doSomethingNefarious()代码将被执行。相似地,<div onclick="doSomethingNefarious()">x</div>

\n

如果您搜索“HTML sanitizer”,您会发现许多不同的库都表示可以为您完成此操作。不过,这个问题非常严重,解决这个问题的方法正在被标准化为Sanitization API。虽然还处于早期阶段,但这是一个非常有前途的发展。使用当前(非常草案)形式的 API,您可以执行以下操作:

\n
export const getFromContent = (html, selector) => {\n    const div = document.createElement("div");\n    div.setHTML(html);  // <== `setHTML` is a new method that sanitizes.\n                        // Here I\'m using the default sanitizer, but you\n                        // could create one with your own custom settings\n                        // and pass it as the second argument\n    let r = div.querySelectorAll(selector);\n    return r;\n};\n
Run Code Online (Sandbox Code Playgroud)\n

但 API 仍在不断变化。

\n