Event delegation on SVG Elements

2019-01-23 03:07发布

I am trying to have a common click handler for all the elements I am appending to a SVG canvas. But I cannot delegate the handler to the newly created elements.

This is the code I have tried to delegate, but no luck

$("#floor").on('click','.drawnLine', function() {
    //#floor is the SVG Element
    //.drawnLine is the <line> element that is added dynamically
    console.log($(this).data('index'));
});

Update: On the jQuery manual of .on() it is mentioned that

Note: Delegated events do not work for SVG.

So now the question is any other workaround for this problem?

2条回答
Summer. ? 凉城
2楼-- · 2019-01-23 03:50

TL/DR: Attach the event listener to a non-SVG parent element.

The note in the jQuery docs is somewhat misleading.

Delegated events do not work for SVG.

It should probably be...

Delegated events do not work when the listener is attached to SVG.

jQuery's event delegation does not work when the event listener is attached to an SVG element; however, if you instead attach the listener to a non-SVG parent of the SVG, event propagation works as expected and any selectors that match SVG elements will indeed trigger your event handler function.

Attaching the listener to the SVG element will not work:

$("#floor").on('click','.drawnLine', function() {
    console.log($(this).data('index'));
});

But attaching it to a parent element will work:

$(document.body).on('click','#floor .drawnLine', function() {
    console.log($(this).data('index'));
});

Note: one quirk I've noticed is that if the event target is an SVG element, the event won't bubble up all the way to document.body on iOS. So if you want iOS users to be able to trigger your handler function you'll need to attach your event listener to some element in between (such as the div element your SVG resides in).

查看更多
\"骚年 ilove
3楼-- · 2019-01-23 04:07

When jQuery fails with SVG you can use vanilla js. Fortunately every browser that supports svg also supports event listeners. The pure js delegated event is not so ugly:

$("#floor")[0].addEventListener('click', function(e) {
  // do nothing if the target does not have the class drawnLine
  if (!e.target.classList.contains("drawnLine")) return;
  console.log($(this).data('index'));
});

But you can also create your own function to delegate your events more cleanly.

查看更多
登录 后发表回答