【问题标题】:Augmenting SVG tag with Shadow DOM使用 Shadow DOM 增强 SVG 标签
【发布时间】:2016-11-25 18:00:00
【问题描述】:

我一直在试验 HTML5 和 SVG;而且我对 JavaScript 和 Web 开发非常陌生,所以我可能缺少一些东西。我正在尝试创建可重用的 Web 组件,利用一些新功能,例如 HTML 导入、Shadow DOM,并扩展现有的 Web 元素。我有两个 html 文件:

test.html

<html>
<head>
  <title>Test HTML5</title>
</head>
<body>
  <link rel="import" href="Elements/tank.html">

  <svg width="100%"
       viewBox="0 0 500 500"
       style="border: solid; border-width: thin; stroke-width: 2;">

    <polyline points="0,300 100,300 100,100 250,100 250,150 500,150"
              style="fill:none;stroke:black;stroke-width:3"
              onclick="window.alert('you clicked line')" />
    <svg is="my-tank" x="200" y="350" width="50" height="50"></svg>

  </svg>
</body>
</html>

tank.html

<html>
<body>
  <template id="tank">
    <rect fill="red" width="50" height="50"></rect>
  </template>

  <script type="text/javascript">
    var tankElement = document.currentScript.ownerDocument.querySelector('#tank');

    document.registerElement('my-tank', {
      prototype: Object.create(SVGSVGElement.prototype, {
        createdCallback: {
          value: function () {
            var root = this.createShadowRoot();
                        
            //Works
            root.innerHTML = tankElement.innerHTML;

            //Doesn't work
            //var tankTemplate = document.importNode(tankElement.content, true);
            //root.appendChild(tankTemplate);
          }
        }
      }),
      extends: 'svg'
    });
  </script>
</body>
</html>

//Works 注释下的代码在 SVG 可绘制空间中绘制了一个红色矩形。 //Doesn't work 下的代码没有绘制任何东西或产生任何错误。

//Works:的截图

//Doesn't work:的截图

我一直在使用 Opera 41.0 进行测试。

【问题讨论】:

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


    【解决方案1】:

    您不能这样做,因为svg 不能是影子主机。只有有限数量的元素可以成为影子宿主:

    article, aside, blockquote, body, div, footer, h1, h2, h3, h6, @98654336@, @987654336 、headermainnavpsectionspan

    所以不仅svg,而且像inputtextarea 这样的其他人都不能有shadow-dom(我说的是Shadow-DOM v1)。

    详见attachShadow的定义:https://dom.spec.whatwg.org/#dom-element-attachshadow

    还要注意:

    • SVGSVGElement 没有实现 HTMLElement
    • 还听说 SVG 在其实现中已经包含一个 shadow-dom,并且带有自定义元素 v1 你可能只有一个 shadow-dom(见这里:http://hayato.io/2016/shadowdomv1/)。

    为什么不创建一个常规的自定义元素,它可能在其 shadow-dom 中包含 &lt;svg&gt; 元素?

    【讨论】:

    • SVG 2 标准规定 &lt;use&gt; 标签使用 shadow DOM。
    • 我认为换句话说,您不能将 SVG 用作 shadow-dom “主机”,这意味着它充当 shadow-root。 FWIWjsfiddle.net/w08pxrfc/15
    • 我不明白 shadow-dom "host" 和 shadow-root 之间的区别。从调试窗格中,它确实显示“shadow-root (open)”。所以我猜一个 svg 标签可以支持某种形式的阴影。它会让我使用innerHTML 操作根,但不能附加子级。我正在使用 Shadow DOM 尝试从我计划稍后介绍的文档 CSS 中封装我的自定义元素。
    • 我尝试使用HTMLElement 原型创建自定义元素&lt;my-tank&gt;,并且registerElement 中没有extends 参数。在正文中使用时会显示红色框,但当自定义元素放置在 svg 标记下时浏览器不会做出反应。 svg 标签下可能不支持自定义元素?
    • 这个评估看起来是正确的。似乎您甚至无法在没有环绕 foreignObject 标记的情况下在 svg 中创建自定义元素,并且现有 svg 标记的扩展似乎仅在基于 Chrome 的浏览器中有效。 IE 的 WebComponents.js ployfill 也以这种方式运行。
    【解决方案2】:

    这是因为在您的&lt;template&gt; 中,&lt;rect&gt; 元素不在&lt;svg&gt; 标记内,所以它不会被识别为SVGRectElement,而是被识别为HTMLUnknownElement

    要使其工作,只需在周围添加&lt;svg&gt; 标签:

    <template id="tank">
        <svg>
            <rect fill="red" width="50" height="50"></rect>
        </svg>
    </template>
    

    现在您可以使用importNode()cloneNode() 导入元素:

    //Works
    var rect = tankElement.content.querySelector('rect').cloneNode();
    root.appendChild(rect);
    

    更新导入多个 SVG 元素

    将元素放入&lt;g&gt;:

    <template id="tank">
        <svg>
            <g>
                <rect fill="red" width="50" height="50"></rect>
                <rect fill="blue" width="25" height="50"></rect>
            </g>
        </svg>
    </template>
    

    克隆&lt;g&gt;及其内容:

    var g = tankElement.content.querySelector('g').cloneNode(true);
    root.appendChild(g);
    

    【讨论】:

    • rect 标签不是SVGRectElement 是有道理的,因为它不在svg 标签内。当我把它放在一个矩形内时,我看到了矩形。但是我遇到了一个尴尬的双 svg 标签情况。有更好的方法吗?有两个嵌套的 svg 标签会影响性能吗?
    • @JustinHuskic 如果您只插入 ,则没有双/嵌套 svg 标签,您可以使用querySelector() 获取。见上面的例子。
    • 优秀。如果我想克隆第一个 svg 标记下的所有内容,而不仅仅是 rect,是否有 javascript 调用可以做到这一点?
    • 您可以将它们放在 标签中,然后使用 cloneNode(true) 克隆 标签及其内容。 developer.mozilla.org/en/docs/Web/SVG/Element/g
    • 我无法使用var tankElement 选择&lt;g&gt; 标记。 childNodes 属性和 querySelector 对“g”的调用变为空。就像模板节点根本没有子节点一样。
    猜你喜欢
    • 2020-08-18
    • 2017-05-24
    • 1970-01-01
    • 1970-01-01
    • 2014-06-04
    • 2013-10-29
    • 1970-01-01
    • 1970-01-01
    • 2017-02-05
    相关资源
    最近更新 更多