在 HTML 中包含资源的新思路

做者:scott jehl

翻译:疯狂的技术宅html

原文:https://www.filamentgroup.com...前端

未经许可严禁转载程序员

注意:这篇文章描述了一种咱们仍须要测其试性能影响的实验技术。 它可能最终会成为一种有用的工具,也有可能成为不被推荐的作法。 不管哪一种方式,它对咱们来讲颇有吸引力!web

只要我一直工做在 Web 上,就须要一种简单的 HTML 驱动方式,将另外一个文件的内容直接包含在页面中。 例如,我常常但愿向页面添加额外的 HTML,或者嵌入 SVG 文件的内容,以便咱们能够为其设置动画和样式。 一般咱们经过使用 JavaScript 获取文件并将其内容附加到特定元素,或者经过在服务器端去包含文件来实现这种嵌入,但在大多数状况下,这些方法都不是咱们想要的。面试

本周我在思考如何用一些新的与 fetch 相关的标记模式来实现这一点,例如 rel="preload" 或 HTML import,但我老是得出的相同结论,即这些都不能使你方便地访问所取得的文件的内容。 而后我想,假设浏览器容许我在父文档中检索 iframe 的内容,也许一个旧的 iframe 多是一个很不错的模式。 事实证实,它确定会的!ajax

一个短小的演示:包含 SVG

下面是一个内联(嵌入式)SVG 图形。它是从外部文件 signal.svg中加载的。segmentfault

要加载并嵌入 SVG 文件,我用了下面的标记:浏览器

<iframe src="signal.svg" onload="this.before((this.contentDocument.body || this.contentDocument).children[0]);this.remove()"></iframe>

尽管此标记以 iframe 开头,但若是你使用开发人员工具检查上面的图形,将会看到 SVG 的图标标记,就内嵌在 HTML DOM 中,并且找不到 iframe 元素。 这是由于代码用 iframe 加载文件,而且在删除 iframe以前,用 onload 事件在 HTML 中 iframe 的位置以前注入了 iframe 里的内容。缓存

该方法也适用于 object 元素,不管如何它一般用于引用SVG,因此我认为这特别好。 对于一个objectsrc 属性必须用 data 替代:安全

<object data="signal.svg" onload="this.before((this.contentDocument.body || this.contentDocument).children[0]);this.remove()"></object>

另外一个演示:包含 HTML 文件

也许更有用......这是一个使用HTML而不是SVG的例子!

能够用下面的标记加载:

<iframe src="/images/includespost/htmlexample.html" onload="this.before((this.contentDocument.body||this.contentDocument).children[0]);this.remove()"></iframe>

一个说明这一个:你可能已经注意到,标记片断检查 contentDocument.body 或仅检查 contentDocument。这是对 HTML 和 SVG 包含进行的规范化检查。 这是必要的,由于即便 HTML 文件自己只包含一个段落元素,浏览器也会建立一个完整的 HTML 文档来包装该段落,并包含 HTML 元素、head、body等。因此该片断会试图获取 iframebody 元素(若是存在),若是不存在,它将会用于整个文档。

值得注意的是,若是你要导入包含多个元素的 HTML 文件,我建议将其所有包装在 div 中,以使 iframe 标记可以简单地查找 body中的第一个子节点。

好处

与咱们过去使用的其余模式相比,这种模式有一些很明显的好处:

  • 这是声明性的。 与大多数自定义 JavaScript 方法不一样,这个方法是 HTML 驱动的,它在标记中的目的很是清楚,一目了然。
  • 它适用于 HTML 或 SVG。 我不肯定你想要包含什么东西,但这至少知足了我本身的需求。
  • 这是异步的! 内容加载不会阻止页面渲染,这是 iframe 的性质。
  • 它是缓存友好的。 与服务器端嵌入不一样,此模式容许咱们包含外部文件,同时容许天然缓存文件以供往后重用。 (使用服务器端包含的内容,在客户端缓存是可能的,但难以作到)。
  • 不管 JavaScript 是否运行,它都会显示内容,由于这就是 iframe 的设计目标。 JavaScript 能够将 iframe 的内容移动到父文档中,即使失败了,你仍会看到包含的内容。
  • 它没有留下任何痕迹:iframe 将内容导入页面后会被删除。 注意:你可能但愿为 iframe 指定 border:0; 甚至能够在加载时安全地隐藏它(或许经过 onerror 事件再次显示它?)。
  • 它适用于各类浏览器:到目前为止,在个人简短测试中,它适用于 Chrome,Firefox,Safari 和 Edge。 IE 会显示 iframe 中的备选内容,但我认为能够经过调整 onload 处理中的 JS 来得到对 IE 的支持,由于它目前用的是 IE 不喜欢的语法。 稍微调整一下,我认为 IE 支持是可能的。
  • 若是你愿意的话,它甚至能够包含在一个 Web 组件中,正如 Andy Bell 巧妙地演示的那样(这是一个更清晰的标记,但就 JS 依赖性来讲更脆弱一点)。

考虑其余可能的用途颇有趣......也许你能够引入 HTML 模块及其相关的 CSS 连接。 或者在文档或博客文章中嵌入推文或代码。 它甚至可能用于异步加载和应用常规的 rel=stylesheet 连接,而且优先级较低,不然很难作到(注意:我没有对这个想法进行太多的测试)。

能够惰性加载吗?是的,很快!

使用 iframe 进行此模式的另外一个好处是, iframe 会在进入视口时得到延迟加载的能力。 这能够用 load ="lazy" 属性来实现,该属性也适用于 img 元素。 代码看起来是这样:

<iframe src="signal.svg" loading="lazy" onload="this.before((this.contentDocument.body||this.contentDocument).children[0]);this.remove()"></iframe>

可能存在的问题

iframe 在 web 上很经常使用,可是在页面中过分使用 iframe 可能会致使性能或内存消耗问题。 例如对页面上全部图标使用可能会太重,可是对于须要进行动画和样式化的特定图标来讲,它可能会很好用。 不过如今我只能作更多的测试。

还有可能存在XSS问题,但我不肯定这与其余须要注意外部内容的状况有什么不一样。 你仍须要作一般的安全检查,而且最好将其看做是同域技术,尽管我也不肯定。

就目前而言,这种作法有但愿成为以前将另外一个文件直接包含在页面中方法的改进。

反馈

咱们将会继续测试这种模式,若是咱们发现了什么有趣的内容,会很快发布后续内容。 若是你有什么反馈或想法,请随时在Twitter(https://twitter.com/filamentg...)上与咱们联系。 谢谢阅读!


本文首发微信公众号:前端先锋

欢迎扫描二维码关注公众号,天天都给你推送新鲜的前端技术文章

欢迎扫描二维码关注公众号,天天都给你推送新鲜的前端技术文章

欢迎继续阅读本专栏其它高赞文章:


相关文章
相关标签/搜索