【问题标题】:Shadow DOM: is it possible to encapsulate JS?Shadow DOM:可以封装 JS 吗?
【发布时间】:2015-02-14 16:04:16
【问题描述】:

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

是否有可能通过一些新的 Web 组件技术——影子 DOM/模板/导入来实现?我能够将 HTML 添加到 shadow DOM 并封装 CSS,但无法确认是否可以为组件的 javascript 执行获取单独的文档。

【问题讨论】:

    标签: javascript html iframe web-component shadow-dom


    【解决方案1】:

    Web-components,通过HTML imports使用,封装了Shadow DOM HTML 相关脚本。

    为了缩小术语范围,假设我们有一个 Polymer 组件 core-ajax。这里是the code。如您所见,它根本不提供任何 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 使用的文档,但 is being discussed 在 w3c 邮件组中使用了将近三年的时间。然而,即使在“我们是否永远不会在作者空间中完全启用它们”等方面,讨论也远未得出结论。

    【讨论】:

    • 谢谢@mudasobwa!通过聚合物加载的脚本是否有单独的文档?我对分离脚本的上下文特别感兴趣,类似于在不同的框架中运行脚本。
    • 我建议您阅读 W3C 进口规范。不,document 是一样的(除了iframe 之外,没有创建另一个嵌入文档的能力,我敢打赌永远不会有这样的能力。)
    • 谢谢! This answer 似乎暗示了以后会通过Shadow DOM来支持这个,但是我很好奇是否已经有其他方法的解决方案了。
    • @Sasha 我已经阅读了讨论,看来我们将来有可能看到您要求的功能。将更新我的答案。
    • 我有一个文档,我现在正试图将其转换为 Shadow DOM 小部件。我对 document.body 进行了引用,并希望将这些引用转换为我的小部件的最外层容器。我引用 document.body 进行事件处理,并且必须可以在一个页面上拥有我的组件的多个实例,并在其内部拥有一个组件的实例。 (我的组件是一个容器。)如果能够使用嵌入式 JS 引用我的影子 DOM 的根目录,将会有很大帮助。
    【解决方案2】:

    这与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 安全地与子 i​​frame 交谈。

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

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

    【讨论】:

      【解决方案3】:

      是的,您可以在模板中添加&lt;style&gt;&lt;script&gt; 标签(sn-p 仅在支持 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。

      但是,这是currently broken by content security policy and is a high XSS risk

      【讨论】:

        猜你喜欢
        • 2017-06-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-10-02
        • 2014-09-08
        • 1970-01-01
        • 2017-02-17
        • 2017-04-18
        相关资源
        最近更新 更多