Ser*_*rov 16 html javascript internet-explorer svg d3.js
我使用这个D3片段将SVG g
元素移动到rest元素的顶部,因为SVG渲染顺序取决于DOM中元素的顺序,并且没有z索引:
d3.selection.prototype.moveToFront = function () {
return this.each(function () {
this.parentNode.appendChild(this);
});
};
Run Code Online (Sandbox Code Playgroud)
我这样运行:
d3.select(el).moveToFront()
Run Code Online (Sandbox Code Playgroud)
我的问题是,如果我添加一个D3事件监听器,d3.select(el).on('mouseleave',function(){})
然后使用上面的代码将元素移动到DOM树的前面,所有事件监听器都在Internet Explorer 11中丢失,在其他浏览器中仍然可以正常工作.我该如何解决它?
一种解决方案是使用事件委托。这种相当简单的范例在 jQuery 中很常见(这让我想到在这里尝试一下。)
通过使用委托事件侦听器扩展d3.selection
原型,我们可以侦听父元素上的事件,但仅当事件的目标也是我们所需的目标时才应用处理程序。
所以而不是:
d3.select('#targetElement').on('mouseout',function(){})
Run Code Online (Sandbox Code Playgroud)
你会使用:
d3.select('#targetElementParent').delegate('mouseout','#targetElement',function(){})
Run Code Online (Sandbox Code Playgroud)
现在,当您移动元素时,或者即使在创建侦听器后添加/编辑/删除元素时,事件是否丢失也没关系。
这是演示。在 Chrome 37、IE 11 和 Firefox 31 上进行了测试。我欢迎建设性的反馈,但请注意,我对 d3.js一点也不熟悉,所以很容易错过一些基本的东西;)
//prototype. delegated events
d3.selection.prototype.delegate = function(event, targetid, handler) {
return this.on(event, function() {
var eventTarget = d3.event.target.parentNode,
target = d3.select(targetid)[0][0];
if (eventTarget === target) {//only perform event handler if the eventTarget and intendedTarget match
handler.call(eventTarget, eventTarget.__data__);
}
});
};
//add event listeners insead of .on()
d3.select('#svg').delegate('mouseover','#g2',function(){
console.log('mouseover #g2');
}).delegate('mouseout','#g2',function(){
console.log('mouseout #g2');
})
//initial move to front to test that the event still works
d3.select('#g2').moveToFront();
Run Code Online (Sandbox Code Playgroud)
根据 Makyen 的有用反馈,我进行了一些改进,以允许将委派侦听器应用于所有匹配的子项。EG“监听 svg 内每个 g 上的鼠标悬停”
这是小提琴。下面的片段。
d3.select('#targetElement').on('mouseout',function(){})
Run Code Online (Sandbox Code Playgroud)
d3.select('#targetElementParent').delegate('mouseout','#targetElement',function(){})
Run Code Online (Sandbox Code Playgroud)
//prototype. delegated events
d3.selection.prototype.delegate = function(event, targetid, handler) {
return this.on(event, function() {
var eventTarget = d3.event.target.parentNode,
target = d3.select(targetid)[0][0];
if (eventTarget === target) {//only perform event handler if the eventTarget and intendedTarget match
handler.call(eventTarget, eventTarget.__data__);
}
});
};
//add event listeners insead of .on()
d3.select('#svg').delegate('mouseover','#g2',function(){
console.log('mouseover #g2');
}).delegate('mouseout','#g2',function(){
console.log('mouseout #g2');
})
//initial move to front to test that the event still works
d3.select('#g2').moveToFront();
Run Code Online (Sandbox Code Playgroud)
与所有委托侦听器一样,如果您将目标元素移到已委托侦听的父级之外,那么该子级的事件自然会丢失。但是,没有什么可以阻止您将事件委托给标签,body
因为您永远不会将孩子移出该标签。例如:
d3.select('body').delegate('mouseover','g',function(){...
Run Code Online (Sandbox Code Playgroud)