简体   繁体   中英

How do you debounce/throttle Shadow DOM events?

I'm attaching an event handler to my shadow element internally (I'm not propagating the event out to the user), handling dragover events. Everything works fine, until I attempt to debounce the events. It seems that when I use setTimeout , the event is changed so that it is as if it was fired on (event target is) <my-element> .

To make this more clear; <my-element> has it's shadow dom which contains some elements. Without setTimeout the event is fired on one of the shadow elements as expected. For example an <li> or <button> in the shadow dom of <my-element> . As soon as I attempt to debounce the events with setTimeout the event target is changed to <my-element> .

So my question is; can/how do you debounce shadow dom events?

HTML

<html>
    <head></head>
    <body>
       <my-element>
           #shadow-root (open)
               <ul>
                   <li draggable="true">
                        <button>Hi</button>
                   </li>
                   <li draggable="true">
                        <button>Hi</button>
                   </li>
               </ul>
              <ul class="drop-target">
              </ul>
       </my-element>
    </body>
</html>

Javascript:

    //...class code
    attachEventHandler(){
        let self = this;

        self.shadowElement.addEventListener('dragover', (function debouncedDragOverFactory(){
            let timeoutId = 0,
                evObj;

            return function debouncedDragOver(ev){
                evObj = ev; //Only tracking the last event
                if(!timeoutId){
                    timeoutId = setTimeout(function(){
                        self.onDragOver(evObj); //self is 'this' pointer of the class this code is in.
                                                //onDragOver handles the drag event, obvisouly. 
                        timeoutId = 0;
                    }, 100);
                }
            };
        })());
    }

[Update]
Here's a Plunker example .

I put a 1s delay to the setTimeout in the second event handler. So you'll see a bunch of 'DIV' node names scroll by then the 'LIST-EXAMPLE' node names.

The div's are in the shadowRoot.

LIST-EXAMPLE is what the user would see on the window scoped events.

To get around the event changing, in the third event handler I copy the data off that I want.

So I guess in my update I answer my own question.

Here's a Plunker example .

I put a 1s delay to the setTimeout in the second event handler. So you'll see a bunch of 'DIV' node names scroll by then the 'LIST-EXAMPLE' node names.

The div's are in the shadowRoot.

LIST-EXAMPLE is what the user would see on the window scoped events.

To get around the event changing, in the third event handler I copy the data off that I want.

So you can do what you would normally do to debounce, but make sure to copy the data that you need off the event, and use the copy in your worker function.

To update my code from above with a possible solution...

//...class code
attachEventHandler(){
    let self = this;

    self.shadowElement.addEventListener('dragover', (function debouncedDragOverFactory(){
        let timeoutId = 0,
            evTarget;

        return function debouncedDragOver(ev){
            evTarget = ev.target; //Copy the data off that I need
            if(!timeoutId){
                timeoutId = setTimeout(function(){
                    self.onDragOver(evTarget);
                    timeoutId = 0;
                }, 100);
            }
        };
    })());
}

You can also pass the data you need as a third parameter of the setTimeout function:

li.addEventListener('dragover', function(e){
    setTimeout(function(nodeName){
        output.textContent = '3' + nodeName + '\n' + output.textContent;    
    }, 2000, e.target.nodeName);
});

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM