【问题标题】:Accessing a DOM object defined in an external SVG file访问在外部 SVG 文件中定义的 DOM 对象
【发布时间】:2011-03-21 17:45:48
【问题描述】:

SVG 标准允许使用和引用外部 SVG 文件。

我有一个文件circle.svg,它定义了一个 ID 为“the_circle”的圆形对象。 从主 SVG 文件中,我可以使用 SVG linking 包含这个圆圈并为其设置动画。

我也想通过 javascript 访问同一个圆形对象,我该怎么做? xlink:href="url(#the_image)#the_circle" 的 javascript 等价物是什么?

使用 document.getElementById('the_image') 我只能访问 SVGImageElement 而不能访问包含的 SVG 中定义的对象。

<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" version="1.1"
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" >

  <image 
    id="the_image"
    x="0" y="0"  width="100%" height="100%"
    xlink:href="circle.svg" />

  <animateTransform     
    xlink:href="url(#the_image)#the_circle"

    attributeName="transform" attributeType="XML"
    type="translate" 
    from="0" to="25"
    dur="1s" repeatCount="indefinite" 
    additive="replace" fill="freeze" />
</svg>

【问题讨论】:

标签: javascript dom svg


【解决方案1】:

看起来“正确”的做法实际上是使用 SVG“使用”元素,而不是图像。原因是SVG使用元素的DOM接口指定了一个属性“instanceRoot”,可以让你获取到那个使用元素对应的“实例树”的根:http://www.w3.org/TR/SVG/struct.html#InterfaceSVGUseElement

因此,您最终会得到如下所示的解决方案: circle.svg:

<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" 
  "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="4in" height="4in" id="the_svg"
     viewBox="0 0 4 4" version="1.1"
     xmlns="http://www.w3.org/2000/svg">
    <circle r="1" fill="blue" stroke="none" id="the_circle"/>
</svg>

使用circle.svg的svg根节点的文档:

<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" 
  "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" id="foo"
     version="1.1"
     xmlns="http://www.w3.org/2000/svg"
     xmlns:xlink="http://www.w3.org/1999/xlink"> 

    <use xlink:href="circle.svg#the_svg"/>
</svg>

不幸的是,虽然 Firefox 支持在外部文档中使用 use 元素,但目前 Webkit 中存在一个不允许这样做的错误:https://bugs.webkit.org/show_bug.cgi?id=12499

此外,Firefox 似乎没有为使用元素实现 instanceRoot 属性。

因此,您可能需要解决当前 SVG 实现的限制。我建议这样做的方法是使用 XMLHttpRequest 下载您想要链接到的文档,并将下载文档的 DOM 导入到您的宿主文档的 DOM 中。以下代码实现了这一点,并适用于 Firefox、Opera 和 Chromium:

<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" 
  "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" id="foo"
     version="1.1"
     xmlns="http://www.w3.org/2000/svg"
     xmlns:xlink="http://www.w3.org/1999/xlink"> 

    <script>
    function fetchXML  (url, callback) {
        var xhr = new XMLHttpRequest();
        xhr.open('GET', url, true);
        xhr.onreadystatechange = function (evt) {
        //Do not explicitly handle errors, those should be
        //visible via console output in the browser.
        if (xhr.readyState === 4) {
            callback(xhr.responseXML);
        }
        };
        xhr.send(null);
    };

    //fetch the document
    fetchXML("http://localhost:8082/tmp/circle.svg",function(newSVGDoc){
        //import it into the current DOM
        var n = document.importNode(newSVGDoc.documentElement,true);
        document.documentElement.appendChild(n);

        var circle = document.getElementById("the_circle"); //now you have the circle
    }) 
    </script>
</svg>

【讨论】:

  • 这正是我想要的!其他通过 XHR 获取 SVG 并将其附加到 DOM 的尝试没有成功。谢谢!
  • 嘿 jbeard4 :) 我试图将您的解决方案用于大型 SVG(900kb),现在在 SVG 加载之前加载代码,然后我无法访问 svg。这是我的问题My Question的链接我想你可以帮助我!
【解决方案2】:

用jQuery/Coffeescript中的代码补充@echo-flow的优秀解决方案:

  $.get '/assets/hexagon.svg', (svgFileData)->
    svgTag = svgFileData.documentElement
    $('body').append(svgTag)
    circle = $('#the_circle')

【讨论】:

  • 不要忘记使用 document.importNode 导入节点。如果你不这样做,它可能会抱怨。
【解决方案3】:

您可以更轻松地访问必要的元素:

document.getElementById('the_image').contentDocument.getElementById('the_circle')

参考this image(取自dev.opera.com

【讨论】:

  • 很好,但有什么收获?我认为这仅适用于同一域中包含的 SVG?
  • 那又怎样?通常,您想要操作您的文件,而不是来自其他网站的文件。
  • 我认为是的;说清楚就好。我同意同域的情况很常见,除非确实需要通用解决方案,否则其他答案会显得有些矫枉过正。
  • 实际上向另一个域发出 ajax 请求也面临同样的问题,除非它允许 CORS。
  • 遗憾的是,这也不适用于file:// URL。相当烦人。
【解决方案4】:

这是使用 React 和 ES6 时解决此问题的方法。用法:

<SvgImage url='pathToImage.svg'></SvgImage>

https://gist.github.com/mikkel/8b79a713ff06bbec379d

【讨论】:

    猜你喜欢
    • 2013-08-17
    • 2012-07-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-12-29
    • 1970-01-01
    • 2021-08-18
    • 1970-01-01
    相关资源
    最近更新 更多