影子dom内部的脚本不起作用

时间:2018-06-29 12:12:09

标签: javascript angular web-component shadow-dom angular-elements

我已经创建并导出了一个Angular Element(Angular中的Web组件)作为单个脚本标签(user-poll.js)。 要使用此Angular元素,我只需要在宿主站点中指定以下两行:

 <user-poll></user-poll>
 <script src="path/to/user-poll.js"></script>

Working JSBin Example

我有以下要求:

  1. 在外部站点上加载多个Angular Elements。
  2. 动态加载所有Angular元素

我遇到了以下问题:

  1. 在站点上加载多个组件会导致Angular冲突,因为每个组件脚本本身就是一个完整的Angular应用。
  2. 为解决冲突问题,我将每个组件加载到单独的 Shadow Dom 组件中(即,在阴影dom容器内添加组件标签和组件脚本文件链接),以便对每个组件进行沙盒处理。但是影子dom内部的组件脚本不起作用。

JSBin example的影子dom内部的动态加载组件

<body>

</body>
    setTimeout(() => {
    loadJS();
}, 2000);
function loadJS() {
    var elm = document.createElement("div");
    elm.attachShadow({mode: "open"});
    elm.shadowRoot.innerHTML = `<user-poll><h2>Custom Web Component - user-poll loaded</h2><script src="https://cdn.rawgit.com/SaurabhLpRocks/795f67f8dc9652e5f119bd6060b58265/raw/d5490627b623f09c84cfecbd3d2bb8e09c743ed4/user-poll.js"><\/\script></user-poll>`;
    document.body.appendChild(elm);
}

那么,在网站上动态加载多个Angular Elements的最佳方法是什么?

1 个答案:

答案 0 :(得分:4)

不执行脚本的事实与Shadow DOM无关,而是与您尝试插入<script>元素的方式有关,即通过innerHTML中的字符串。 在这种情况下,不会解释字符串,也不执行脚本。

如果要使其正常工作,必须通过<script>插入appendChild()

您可以直接添加通过<script>创建的createElement()元素,或使用<template>元素来直接做到这一点。

1。与createElement()

创建一个<script>元素并将其附加到其父元素:

var up = document.createElement( 'user-poll' )
var script = document.createElement( 'script' )
script.textContent = 'document.write( "executed" )'
up.appendChild( script )
elm.attachShadow( { mode: 'open' } )
   .appendChild( up )
<div id="elm"></div>

2。带有<template>标签

附加<template>元素的内容:

elm.attachShadow( { mode: 'open' } )
   .appendChild( tpl.content )
<template id="tpl">
    <user-poll>
        <script>document.write( 'exected' )</script>
    </user-poll>
</template>

<div id="elm"></div>

在解析<template>元素时不执行脚本,而是在将其content附加到DOM时执行脚本。

PS :无论如何,我不确定这是加载多个Angular元素的最佳方法:Shadow DOM不会像<iframe>那样充当Javascript代码的沙箱。相反,也许您必须使用模块加载器。