Javascript Chrome在记录克隆的SVGElement时添加属性[requiredExtensions,systemLanguage] 问题

Javascript Chrome在记录克隆的SVGElement时添加属性[requiredExtensions,systemLanguage] 问题,javascript,google-chrome,svg,Javascript,Google Chrome,Svg,正在处理SVGElements上的转换,发现了一些我不理解的东西 基本上,我尝试使用cloneNode(true)克隆一个现有的SVGElement,并使用transform.baseVal.getItem(0.setMatrix()更改其矩阵。只要我不使用console.log()记录新的SVGElement,这一切都可以正常工作 这里有一个例子 必须检查实际的控制台,而不是代码段的内联输出 ;window.onload=函数(){ var tSVG=document.querySelect

正在处理
SVGElements
上的转换,发现了一些我不理解的东西

基本上,我尝试使用
cloneNode(true)
克隆一个现有的
SVGElement
,并使用
transform.baseVal.getItem(0.setMatrix()
更改其矩阵。只要我不使用
console.log()
记录新的
SVGElement
,这一切都可以正常工作

这里有一个例子 必须检查实际的控制台,而不是代码段的内联输出

;window.onload=函数(){
var tSVG=document.querySelector('svg');
var tSVGElement=tSVG.querySelector('#AL>g');
var tSVGElement2=tSVGElement.cloneNode(1);
var tMatrix=tSVGElement2.transform.baseVal.numberOfItems?tSVGElement2.transform.baseVal.getItem(0)。矩阵:tSVGElement2.transform.baseVal.appendItem(tSVG.createSVGTransform())。矩阵
控制台日志(1,tSVGElement2);
tMatrix2.e+=50;
t矩阵x2.f+=50;
tSVGElement2.transform.baseVal.getItem(0).setMatrix(tMatrix)
tSVGElement.parentNode.appendChild(tSVGElement2);
控制台日志(2,tSVGElement2);
};

对于您的“为什么”问题:

var tSVG = document.querySelector('svg');
  var tSVGElement = tSVG.querySelector('#AL > g');
  var tSVGElement2 = tSVGElement.cloneNode(1);
  watch(tSVGElement2,tSVGElement.parentNode/*Or tSVG since subtree:true*/);
....
我为此打开了一个问题,经chrome()确认,这似乎是一个bug。原因是:

我猜这是由属性同步引起的,而console.log触发它的原因是它枚举了所有属性,从而为systemLanguage/requiredExtensions创建了撕裂/包装器,这反过来又使它们需要同步


预编辑:似乎我对名称空间未被继承的看法是错误的,一件有趣的事情是,尽管
'requireExtensions'
属性应该设置为“true”或不存在,以便元素呈现。这是SVG spec@5.7.1的一部分,通常在
开关
元素上设置属性(以及
systemLanguage
)。有趣的是,在主线程中对克隆的g进行控制台操作时,会使用值
“”添加此属性,该值会转换为false,并导致元素无法呈现

但是,如果等待事件循环完成并记录日志,则属性不存在,请参见此

作为结论,如果克隆g节点并在不将其附加到树的情况下对其进行控制台日志记录,则会显示这些属性,并且不会呈现元素。虽然我不知道这是故意的行为还是一个bug

解决方案

在行为得到解决之前,我必须使用一个微任务队列,因为显然属性是在调用appendChild时添加的:

SVGGraphicsElement.prototype.appendChild = (function(append){
    return function(node){
        setTimeout(function(){
        node.removeAttribute("requiredExtensions");
        node.removeAttribute("systemLanguage");
    },0);
        return append.apply(this,arguments);
    }
}(SVGGraphicsElement.prototype.appendChild));

解决方案2:

var tSVG = document.querySelector('svg');
  var tSVGElement = tSVG.querySelector('#AL > g');
  var tSVGElement2 = tSVGElement.cloneNode(1);
  watch(tSVGElement2,tSVGElement.parentNode/*Or tSVG since subtree:true*/);
....
显然,您必须修补修改DOM树的其他函数,如inserNode等。在这种情况下,变异观察者提供了更通用的解决方案。您可以与不同的家长一起观看多次,相同的观察者将被回收:

function watch(node,parentNode){
    var config = watch._config,
                callback = function(list,observer){
            list.forEach(function(d,i){
                            if(d.type !== "childList"){return}
                            if(
                                Array.prototype.slice.call(d.addedNodes)
                                .some(function(d,i){
                                    return d === node
                                })
                            ) {
                                console.log("added??");
                                setTimeout(function(){
                                node.removeAttribute("requiredExtensions");
                                node.removeAttribute("systemLanguage");
                            },0);
                                observer.disconnect();
                            }
                        })
        },
                observer = node._observer || (node._observer = new MutationObserver(callback));
        observer.observe(parentNode,config);
        return node;
}
watch._config = {childList:true,subtree:true};
使用:

var tSVG = document.querySelector('svg');
  var tSVGElement = tSVG.querySelector('#AL > g');
  var tSVGElement2 = tSVGElement.cloneNode(1);
  watch(tSVGElement2,tSVGElement.parentNode/*Or tSVG since subtree:true*/);
....
进入DOM后,观察者被断开连接,属性被删除,您可以修改该函数,并提供一个属性列表,以便根据需要进行更改。请参见此操作



~~之所以会发生这种情况,是因为您没有克隆整个
svg
,而是克隆
g
,此时没有为此
g
定义
xmlns
,因为它是从其
所有者vg
继承的。当您将它附加到其父级svg
svg
时,浏览器就知道它是svg的一部分。如果您在
tSVGElement.parentNode.appendChild(tSVGElement2)
之后进行控制台日志记录,那么它的输出应该很好。~~

遗憾的是,即使在附加属性之后,属性仍然会保留。我更新了剪下的片段,以便您可以自己查看。如果删除id属性会发生什么?您是指父对象?是的,这就是您要克隆的。我克隆它的子对象,而不是对象本身。组
I clone只有一个转换。听起来像是一个Chrome bug。你有没有向Chrome的bugtracker报告过,或者看看是否有其他人报告过?@Robert Longson:我检查过,但还没有报告我自己。但它也出现在IE11和Edge中,只是在克隆元素的所有子元素上添加了属性。你总是给我同样的回答:-)如果你向浏览器的错误追踪者报告一个错误,它可能会被修复。我们能为您做些什么?也就是说,除了“你发现了一个bug”之外,你还想在答案中寻找什么?经chrome确认,这是一个bug。请参阅更新的answer@ibrahim谢谢。不幸的是,IE支持的答案仍然悬而未决,我猜他们没有chromium团队快:-)我会接受你的帖子,因为你回答了我的主要问题。