javascript - 第二次出现 SVG 样式问题 : chrome only

标签 javascript google-chrome dom svg

这是一个奇怪的问题。

我的页面上有一个 SVG

function addClone()
{
    //loadXMLDoc();
    var svg = document.getElementById("svg");
    var selected = document.getElementById("ID_obj8e530fe7-9e8b-474e-a48b-9c26418b84a6");
    var targetElement = selected.cloneNode(true);
    var namespace = "http://www.w3.org/2000/svg";
    var dummySvg = document.createElementNS(namespace, "svg");
    dummySvg.appendChild(targetElement);
    svg.appendChild(dummySvg);
    //Doing my stuff here with newly appended dummy element.
    debugger;
    svg.removeChild(dummySvg);            
}
<div id="svg_cont">
        <svg id="svg" class="main-svg" width="100%" height="100%" viewBox="0 0 800 380" preserveAspectRatio="xMidYMid meet">
            <defs>
            </defs>
            <g id="layerWrapper" class="svg-view" transform="translate(0,0) scale(1)">
                <svg id="mySection" class="section-view">
                    <g id="svg-view" class="svg-view">
                        <path d="M1,1 L790,1L790,610L1,610Z" class="svg-drawing-boundary"></path>
                        <svg id="ID_obj8e530fe7-9e8b-474e-a48b-9c26418b84a6" class="prj-asset prj-obj cursor-move">
                            <g transform="translate(267.15603585942523,116.72438293625564)rotate(345,72.94356588618024,44.27289336989671)skewX(0)scale(11.011481407032758,6.1897008108322416)">
                                <svg xmlns:v="http://schemas.microsoft.com/visio/2003/SVGExtensions/" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
                                     width="13.248637" height="14.106602" viewBox="0 0 10.59891 11.285281" xml:space="preserve" color-interpolation-filters="sRGB" class="st3"
                                     id="svg3041" version="1.1" style="font-size:12px;fill:none;stroke-linecap:square;stroke-miterlimit:3;overflow:visible"> 
                                <style type="text/css" id="style3043">
                                    .st1 {
                                        fill: url(#grad0-4);
                                        stroke: #000000;
                                        stroke-linecap: round;
                                        stroke-linejoin: round;
                                        stroke-width: 0.72;
                                    }

                                    .st2 {
                                        fill: #ffffff;
                                        font-family: Arial;
                                        font-size: 0.666664em;
                                    }

                                    .st3 {
                                        fill: none;
                                        fill-rule: evenodd;
                                        font-size: 12px;
                                        overflow: visible;
                                        stroke-linecap: square;
                                        stroke-miterlimit: 3;
                                    }
                                    </style> 
                                <defs id="Patterns_And_Gradients"> 
                                <linearGradient id="grad0-4" x1="-0.36884788" y1="586.81169" x2="10.490556" y2="586.81169" gradientTransform="scale(0.97601216,1.0245774)" gradientUnits="userSpaceOnUse"> 
                                <stop offset="0" stop-color="#ff00ff" stop-opacity="1" id="stop3047"></stop> 
                                <stop offset="1" stop-color="#00ffff" stop-opacity="1" id="stop3049"></stop> 
                                    </linearGradient> 
                                </defs> 
                                <g v:index="2" id="g3051" transform="translate(0.36000001,-601.07501)"> 
                                <g id="shape3133-1"> <title id="title3056">Unit 1</title> <desc id="desc3058">1</desc> 
                                <v:textblock v:margins="rect(5,4,4,2.5)"></v:textblock> <v:textrect cx="4.93945" cy="606.797" width="9.88" height="10.4063"></v:textrect> 
                                <rect x="0" y="601.59399" width="9.8789101" height="10.4063" class="st1" id="rect3060" style="fill:url(#grad0-4);stroke:#000000;stroke-width:0.72000003;stroke-linecap:round;stroke-linejoin:round"></rect> 
                                <text x="4.5" y="609.70001" class="st2" id="text3062" style="fill: rgb(255, 255, 255); font-family: Arial; text-anchor: middle; font-size: 8px;">A</text> 
                                            </g> 
                                            </g> 
                                        </svg>
                            </g>
                        </svg>
                        <svg id="ID_obj825f0b13-b5f1-42d2-813f-115805a1f5ea" class="prj-asset prj-obj cursor-move">
                            <g transform="translate(477.2921885223701,123.05810552726564)rotate(0,40.924776199309576,58.01807016243163)skewX(0)scale(6.177956123046479,8.111382018451938)">
                                <svg xmlns:v="http://schemas.microsoft.com/visio/2003/SVGExtensions/" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
                                     width="13.248637" height="14.106602" viewBox="0 0 10.59891 11.285281" xml:space="preserve" color-interpolation-filters="sRGB" class="st3"
                                     id="svg3041" version="1.1" style="font-size:12px;fill:none;stroke-linecap:square;stroke-miterlimit:3;overflow:visible"> 
                                <style type="text/css" id="style3043">
                                    .st1 {
                                        fill: url(#grad0-4);
                                        stroke: #000000;
                                        stroke-linecap: round;
                                        stroke-linejoin: round;
                                        stroke-width: 0.72;
                                    }

                                    .st2 {
                                        fill: #ffffff;
                                        font-family: Arial;
                                        font-size: 0.666664em;
                                    }

                                    .st3 {
                                        fill: none;
                                        fill-rule: evenodd;
                                        font-size: 12px;
                                        overflow: visible;
                                        stroke-linecap: square;
                                        stroke-miterlimit: 3;
                                    }
                                    </style> 
                                <defs id="Patterns_And_Gradients"> 
                                <linearGradient id="grad0-4" x1="-0.36884788" y1="586.81169" x2="10.490556" y2="586.81169" gradientTransform="scale(0.97601216,1.0245774)" gradientUnits="userSpaceOnUse"> 
                                <stop offset="0" stop-color="#ff00ff" stop-opacity="1" id="stop3047"></stop> 
                                <stop offset="1" stop-color="#00ffff" stop-opacity="1" id="stop3049"></stop> 
                                            </linearGradient> 
                                            </defs> 
                                <g v:index="2" id="g3051" transform="translate(0.36000001,-601.07501)"> <g id="shape3133-1"> 
                                <title id="title3056">Unit 1</title> <desc id="desc3058">1</desc> 
                                <v:textblock v:margins="rect(5,4,4,2.5)"></v:textblock> 
                                <v:textrect cx="4.93945" cy="606.797" width="9.88" height="10.4063"></v:textrect> 
                                <rect x="0" y="601.59399" width="9.8789101" height="10.4063" class="st1" id="rect3060" style="fill:url(#grad0-4);stroke:#000000;stroke-width:0.72000003;stroke-linecap:round;stroke-linejoin:round"></rect>
                                <text x="4.5" y="609.70001" class="st2" id="text3062" style="fill: rgb(255, 255, 255); font-family: Arial; text-anchor: middle; font-size: 8px;">C</text> 
                                            </g> 
                                            </g> 
                                        </svg>
                            </g>
                        </svg>
                        <svg id="ID_objdb7111ea-a3eb-4747-abbc-52dc05a80a75" class="prj-asset prj-obj cursor-move">
                            <g transform="translate(137.62939022284382,148.43016162573252)rotate(43,39.73522235650188,37.15088161767568)skewX(0)scale(5.998387475707924,5.193986990973449)">
                                <svg xmlns:v="http://schemas.microsoft.com/visio/2003/SVGExtensions/" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
                                     width="13.248637" height="14.106602" viewBox="0 0 10.59891 11.285281" xml:space="preserve" color-interpolation-filters="sRGB" class="st3"
                                     id="svg3041" version="1.1" style="font-size:12px;fill:none;stroke-linecap:square;stroke-miterlimit:3;overflow:visible"> 
                                <style type="text/css" id="style3043">
                                    .st1 {
                                        fill: url(#grad0-4);
                                        stroke: #000000;
                                        stroke-linecap: round;
                                        stroke-linejoin: round;
                                        stroke-width: 0.72;
                                    }

                                    .st2 {
                                        fill: #ffffff;
                                        font-family: Arial;
                                        font-size: 0.666664em;
                                    }

                                    .st3 {
                                        fill: none;
                                        fill-rule: evenodd;
                                        font-size: 12px;
                                        overflow: visible;
                                        stroke-linecap: square;
                                        stroke-miterlimit: 3;
                                    }
                                    </style> 
                                <defs id="Patterns_And_Gradients"> 
                                <linearGradient id="grad0-4" x1="-0.36884788" y1="586.81169" x2="10.490556" y2="586.81169" gradientTransform="scale(0.97601216,1.0245774)" gradientUnits="userSpaceOnUse"> 
                                <stop offset="0" stop-color="#ff00ff" stop-opacity="1" id="stop3047"></stop> 
                                <stop offset="1" stop-color="#00ffff" stop-opacity="1" id="stop3049"></stop> 
                                            </linearGradient> 
                                            </defs> 
                                <g v:index="2" id="g3051" transform="translate(0.36000001,-601.07501)"> <g id="shape3133-1">
                                <title id="title3056">Unit 1</title> <desc id="desc3058">1</desc> 
                                <v:textblock v:margins="rect(5,4,4,2.5)"></v:textblock> 
                                <v:textrect cx="4.93945" cy="606.797" width="9.88" height="10.4063"></v:textrect> 
                                <rect x="0" y="601.59399" width="9.8789101" height="10.4063" class="st1" id="rect3060" style="fill:url(#grad0-4);stroke:#000000;stroke-width:0.72000003;stroke-linecap:round;stroke-linejoin:round"></rect> 
                                <text x="4.5" y="609.70001" class="st2" id="text3062" style="fill: rgb(255, 255, 255); font-family: Arial; text-anchor: middle; font-size: 8px;">B</text> </g> </g> </svg>
                            </g>
                        </svg>
                    </g>
                </svg>
            </g>
        </svg>
    </div>
    <div>
        <input type="button" value="click" onclick="addClone();" />
    </div>

注意:为了在此代码段中快速构建它,我添加了一个按钮而不是选择元素。 - 要重现此问题 - 在 chrome 浏览器上运行此代码段并单击按钮 2 次。保持您的开发人员窗口打开,以便它可以访问调试器。

在选择任何 svg 元素时,我在我的 js 中执行以下过程。

克隆选定的元素,在克隆的元素上应用一些转换来执行一些其他过程,然后将其附加到我的主 svg。将克隆的元素附加到我的主 svg 后,我正在计算它的边界框,然后根据我的要求对其进行处理。

一旦我的任务完成,我将从我的主 svg 中删除添加的克隆元素。

当我删除克隆元素时会出现问题——它会从 svg 上的所有元素中删除样式效果(特别是图案和渐变效果),尽管所有元素都包含其样式、图案和渐变。 如果我去源然后我原来的 svg 是不变的。

这个问题不是第一次出现,而是从第二次开始出现。

我可以看到我所有的 svg 元素都具有完全相同的 <defs><style>这可能是问题所在,但我无法改变原始 svg 元素的样子——它具有样式、def 和其他无法修改的东西(因为它们是自定义的。用户可以创建自己的模板并在系统中上传然后他们可以在页面上显示这些内容)。

当我尝试在这篇文章中创建示例 fiddle /片段时,它工作正常。当我尝试调试它时,它产生了与我在我的应用程序中遇到的问题相同的问题(在我的应用程序中,它甚至在没有调试的情况下运行时也会发生)。

使用 d3 js,浏览器:chrome,在 Mozilla 中运行良好。

最佳答案

我之前在 Chrome 和其他浏览器中看到过这种和类似的行为,基本上这就是似乎发生的事情:

当您创建 SVG 并且浏览器在内部解析表示时,它解析对 defs 部分的引用(那些使用 url(#someId) 的元素并连接内部引用以指向这些元素。

现在,如果您克隆 SVG,您会在同一文档中获得更多具有相同 ID 的元素,因此引用变得不明确。然而,大多数浏览器引擎仍然对此感到满意(据我所知,还有各种浏览器版本的实现拒绝解析任何元素,而是显示 SVG,就好像根本没有引用一样,这导致大多数时候是黑色填充并且没有渐变,但有时在 use 元素的情况下也会丢失元素。

然而,Chrome 似乎很高兴并在内部引用了一个目标元素(第一个?)。现在的问题是当您删除 Chrome 当前定位的元素时。实现可以注意到这一点并将删除内部引用,而不是试图查看文档中是否确实存在具有相同 id 的另一个元素(无论如何不应该存在)。没有它可以解析到的元素,它的行为就好像链接指向一个不存在的元素并呈现相应的默认图形。

如果您需要处理用户内容,我在这里看到了多种可能的解决方案。我们也为我们的商业图书馆实现了这些解决方案,它们适用于所有浏览器:

a) 不要克隆 defs 部分,而是累积所有不同的 defs 部分。将 defs 元素与真正的“内容”分开,只克隆内容。删除“内容”部分中的 ID。

b) 解析引用和相应的 ID,并使用新的、不冲突的 ID 调整它们。

c) 将完整的自定义 SVG 编码为数据 URL,并将其包含在容器 SVG 中的 svg image 标记中。通过这种方式,您基本上可以获得多个文档,每个文档都有自己的 id 命名空间,因此它们在复制时不会发生冲突。这也可以防止跨站点脚本攻击,因为 Javascript 和所有其他东西基本上都将被沙盒化并且无法再访问您的 HTML 文档。

关于javascript - 第二次出现 SVG 样式问题 : chrome only,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30800735/

相关文章:

javascript - 如何根据下拉框中选择的项目 ID 将文本框(循环)的值从 View 传递到 Controller ?

javascript - 正则表达式不适用于 Firefox,但适用于 Chrome

google-chrome - Chrome 扩展程序 : how to constantly check URLs on new tabs and then respond with an action for certain URLs?

php - Laravel - 将 HTML Dom-Parser 响应保存到数据库

javascript - React项目不在windows上运行,但在ubuntu上运行

javascript - 如果跨度存在,则将类添加到链接

javascript - 如何停止清除浏览器控制台代码历史记录?

php - DOM XML 子节点

python - Python 中的 HTML 结构差异

javascript - jQuery 与 GQuery 基准测试