Shadow DOM:是否可以封装JS

Shadow DOM: is it possible to encapsulate JS?

本文关键字:封装 JS 是否 DOM Shadow      更新时间:2023-11-11

我正试图找到一种不使用iframe封装Javascript的方法。理想情况下,我想要一种在父页面上加载外部HTML组件(小部件)的方法,而不需要使用iframe附带的两步加载过程(首先加载宿主页面,然后才加载iframe内容)。

使用一些新的web组件技术(shadow DOM/templates/imports)有可能实现这一点吗?我能够将HTML添加到shadow DOM并封装CSS,但无法确认是否可以为组件的javascript执行获得一个单独的文档。

通过HTML导入使用的Web组件封装了Shadow DOM HTML相关脚本。

为了缩小术语范围,让我们考虑一下我们有一个以ajax为核心的Polymer组件。这是代码。正如您可能看到的,它根本不提供任何HTML标记,只封装脚本

一旦在主机网页上导入为:

<link 
  rel="import"
  href="https://www.polymer-project.org/components/core-ajax/core-ajax.html"> 

该组件提供了在没有任何javascript编码的情况下执行AJAX调用的能力:

<core-ajax
  auto
  url="http://gdata.youtube.com/feeds/api/videos/"
  params='{"alt":"json", "q":"chrome"}'
  handleAs="json"
  response='{{response}}'
</core-ajax>

以上操作将加载(由于设置了auto属性)指定URL的内容,并将响应放入绑定的response变量中。与该组件通信的另一种方式是提供处理程序,而不是将模板变量绑定到响应:

  - response='{{response}}'
  + on-core-response="{{handleResponse}}"

可以在页面的javascript中实现handleResponse函数,仅此而已

UPD尽管目前无法区分主文档和shadow DOM使用的文档,但w3c邮件组已经讨论了近三年这一功能。尽管如此,讨论还远未结束,甚至在"我们是否从未在作者空间中完全启用它们"等方面也是如此

这与shadow-dom无关,但与完全使用javascript封装组件有关:https://benfrain.com/sandbox-local-htmlcss-code-snippets-inside-iframe-style-guidespattern-libraries/

基本上,您创建了一个iframe节点,并将css和javascript注入其中:

var newIframe = document.createElement('iframe')
newIframe.contentWindow.document.open('text/html', 'replace')
var content = '<!DOCTYPE html><html><head>'+CSS+'</head><body>'+HTML+JS+'</body></html>'
newIframe.contentWindow.document.write(content)
newIframe.contentWindow.document.close()

为了完全隔离javascript访问其父页面,我相信您可以用某种随机生成的域修改父页面的document.domain,这样,对于新的iframe,父页面将看起来像是在不同的域中,并且无法更改其域以匹配。这将伴随着所有常见的安全限制。然后,您可以通过postmessage安全地与孩子iframe交谈。

理论上,您还可以实现一些通信,根据其内容自动调整iframe元素的大小,模拟流中的非iframe元件。

这是我将来想尝试的东西,但还没有尝试过。

是的,您可以在模板中添加<style><script>标记(代码片段仅在支持Shadow DOM的浏览器中运行):

// Create the shadow DOM
var shadow = document.querySelector('#testOutput').createShadowRoot();
// Get the template fragment and add it to the shadow DOM
shadow.appendChild(document.querySelector('#testTemplate').content);
<template id="testTemplate">
  <script>
    alert('Hello from the component');
  </script>
</template>
<div id="testOutput">shadow</div>

或者您可以将它们直接添加到Shadow DOM中。

然而,这目前被内容安全策略打破,是一个高XSS风险。