如何使用 Javascript 访问 SVG 元素

Posted

技术标签:

【中文标题】如何使用 Javascript 访问 SVG 元素【英文标题】:How to access SVG elements with Javascript 【发布时间】:2011-02-14 18:34:01 【问题描述】:

我正在搞乱 SVG,我希望我可以在 Illustrator 中创建 SVG 文件并使用 javascript 访问元素。

这是 Illustrator 启动的 SVG 文件(它似乎还在我删除的文件的开头添加了一堆垃圾)

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
       viewBox="0 0 276.843 233.242" enable-background="new 0 0 276.843 233.242"
     xml:space="preserve">
<path id="delta" fill="#231F20" d="M34.074,86.094L0,185.354l44.444,38.519l80.741-0.74l29.63-25.186l-26.667-37.037
    c0,0-34.815-5.926-37.778-6.667s-13.333-28.889-13.333-28.889l7.407-18.519l31.111-2.963l5.926-21.481l-12.593-38.519l-43.704-5.185
    L34.074,86.094z"/>
<path id="cargo" fill="#DFB800" d="M68.148,32.761l43.704,4.445l14.815,42.963l-7.407,26.667l-33.333,2.963l-4.444,14.074
    l54.074-1.481l22.222,36.296l25.926-3.704l25.926-54.074c0,0-19.259-47.408-21.481-47.408s-31.852-0.741-31.852-0.741
    l-19.259-39.259L92.593,8.316L68.148,32.761z"/>
<polygon id="beta" fill="#35FF1F" points="86.722,128.316 134.593,124.613 158.296,163.872 190.889,155.724 214.593,100.909 
    194.593,52.02 227.186,49.057 246.444,92.02 238.297,140.909 216.074,172.761 197.556,188.316 179.778,169.798 164.963,174.983 
    163.481,197.946 156.815,197.946 134.593,159.428 94.593,151.279 "/>
<path class="monkey" id="alpha" fill="#FD00FF" d="M96.315,4.354l42.963,5.185l18.519,42.222l71.852-8.148l20.74,46.667l-5.926,52.593
    l-24.444,34.074l-25.185,15.555l-14.074-19.259l-8.889,2.964l-1.481,22.222l-14.074,2.963l-25.186,22.963l-74.074,4.444
    l101.481,4.444c0,0,96.297-17.777,109.63-71.852S282.24,53.983,250.389,20.65S96.315,4.354,96.315,4.354z"/>
</svg>

您可能会看到,每个元素都有一个 ID,我希望能够使用 Javascript 访问单个元素,这样我就可以更改 Fill 属性并响应点击等事件。

html 很基础

<!DOCTYPE html>
<html>
    <head>
        <title>SVG Illustrator Test</title> 
    </head>
    <body>

        <object data="alpha.svg" type="image/svg+xml" id="alphasvg"  ></object>

    </body>
</html>

我想这真的是两个问题。

    是否可以这样做,而不是使用 Raphael 或 jQuery SVG 之类的东西。

    如果有可能,技术是什么?


更新

目前,我使用 Illustrator 创建 SVG 文件,我使用 Raphaël JS 创建路径并简单地从 SVG 文件复制点数据并将其粘贴到 path() 函数中。通过手动编码点数据来创建地图可能需要的复杂路径(据我所知)非常复杂。

【问题讨论】:

【参考方案1】:

与使用 Raphael 或 jQuery SVG 之类的东西相比,是否可以这样做?

肯定的。

如果可能,技术是什么?

这个带注释的代码 sn-p 有效:

<!DOCTYPE html>
<html>
    <head>
        <title>SVG Illustrator Test</title> 
    </head>
    <body>

        <object data="alpha.svg" type="image/svg+xml"
         id="alphasvg"  ></object>

        <script>
            var a = document.getElementById("alphasvg");

            // It's important to add an load event listener to the object,
            // as it will load the svg doc asynchronously
            a.addEventListener("load",function()

                // get the inner DOM of alpha.svg
                var svgDoc = a.contentDocument;
                // get the inner element by id
                var delta = svgDoc.getElementById("delta");
                // add behaviour
                delta.addEventListener("mousedown",function()
                        alert('hello world!')
                , false);
            , false);
        </script>
    </body>
</html>

请注意,此技术的一个限制是它受同源策略的限制,因此alpha.svg 必须与.html 文件托管在同一域中,否则将无法访问对象的内部 DOM .

重要的事情要运行此 HTML,您需要将 HTML 文件托管到 Web 服务器,如 IIS、Tomcat

【讨论】:

关于@jbeard4 的注释:在某些浏览器中,这种同源策略导致需要使用服务器(即使您的代码仅使用 html 和 js [服务器端])访问政策将阻止对 svg 的访问。 运行此 HTML 很重要,您需要将 HTML 文件托管到 IIS、Tomcat 等 Web 服务器 正如@HienNguyen 提到的,在网络服务器上运行它之前,它不起作用。 document.getElementById("alphasvg").contentDocument 的返回值为 null TL;DR: contentDocument 从 HTML 上下文到 SVG 上下文的桥梁【参考方案2】:

如果您使用 jQuery,则需要等待 $(window).load,因为在 $(document).ready 处可能尚未加载嵌入的 SVG 文档

$(window).load(function () 

    //alert("Document loaded, including graphics and embedded documents (like SVG)");
    var a = document.getElementById("alphasvg");

    //get the inner DOM of alpha.svg
    var svgDoc = a.contentDocument;

    //get the inner element by id
    var delta = svgDoc.getElementById("delta");
    delta.addEventListener("mousedown", function() alert('hello world!'), false);
);

【讨论】:

使用此代码时,其他答案可能是一个有用的补充:***.com/a/5990945/1515819 如果是 jQuery,你最好使用 $('#alphasvg').load 而不是 $(window).load。这将允许您即时更改属性data 请注意,虽然您可以使用 jQuery 访问 svg 中的元素,但不能使用它来将元素附加到 svg。请参阅***.com/questions/3642035/… 了解原因。【参考方案3】:

如果您对 SVG 使用 &lt;img&gt; 标记,那么您无法操纵其内容(据我所知)。

正如接受的答案所示,使用&lt;object&gt; 是一种选择。

我最近需要这个,并在我的 gulp 构建期间使用 gulp-inject 将 SVG 文件的内容作为 &lt;svg&gt; 元素直接注入 HTML 文档,然后使用 CSS 选择器和 @987654326 非常容易使用@/getElementBy*.

【讨论】:

img 标签对大 SVG 负载很有用...要使用复杂(和交互式!)SVG 最好使用D3js,就像一个精简的 jQuery,专门用于 SVG+DOM +数据操作。

以上是关于如何使用 Javascript 访问 SVG 元素的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 JavaScript 在 <object> 标记内选择 SVG 元素?

如何使用 javascript 将 css 类分配给 svg 元素的标题?

如何访问与 D3 SVG 对象相关的 DOM 元素?

如何使用javascript动态更改html中svg的文本内容

如何获取 svg:g 元素的宽度

使用 Javascript 动态添加时,SVG 元素无法正确缩放