Javascript Events, Capturing works Bubbling doesn&

2020-04-15 15:06发布

My understanding of JS event propagation is that an event first "captures" down the DOM tree, then "bubbles" back up, triggering handlers along the way.

<html>
<body>
    <div id="textbox">
        nothing yet
    </div>
</body>

<script>
    // Gets incremented by "update" event
    var val = 0;

    // Event starts here
    textbox = document.getElementById("textbox");
    textbox.addEventListener("update", function(e) {
        textbox.innerHTML = val;
    }, false);

    // Should bubble here
    body = document.getElementsByTagName("body")[0];
    body.addEventListener("update", function(e) {
        val++;
    }, false); 

    function update() {
        var e = new Event("update");

        textbox.dispatchEvent(e);
    }

    setInterval(update, 10);
</script>
</html>

In my code here there is a div "textbox" inside the body. I think the update event sent to the textbox should bubble up to the body, but it doesn't. The counter never updates.

If I set the UseCapture argument of the body's event listener to true, the counter updates.

Why does capturing work, but not bubbling?

4条回答
爱情/是我丢掉的垃圾
2楼-- · 2020-04-15 15:43

If you use the old (unfortunately deprecated) way, it does bubble. See https://jsfiddle.net/py9vyr7h/1/

function update() {
    var event = document.createEvent('CustomEvent');
    // Second param says to bubble the event
    event.initEvent('update', true, true);
    textbox.dispatchEvent(event);
}
查看更多
成全新的幸福
3楼-- · 2020-04-15 15:49

To get the effect you want (show nothing yet, then 0,1,2,...) you need to follow a couple of the previous answers, plus set capturing on the textbox. (otherwise you'll see show nothing yet, 1, 2,...). First you need to set bubbling to true on your event - like this:

function update() {
    var e = new Event("update",{bubbles:true});
    textbox.dispatchEvent(e);
}

Then you need to capture the event (set to true) - like this:

// Event starts here
textbox = document.getElementById("textbox");
textbox.addEventListener("update", function(e) {
    textbox.innerHTML = val;
}, true);

So everything looks like this:

// Event starts here
textbox = document.getElementById("textbox");
textbox.addEventListener("update", function(e) {
    textbox.innerHTML = val;
}, true);

// Should bubble here
body = document.getElementsByTagName("body")[0];
body.addEventListener("update", function(e) {
    val++;
    console.log(val)
}, false);


function update() {
    var e = new Event("update",{bubbles:true});
    textbox.dispatchEvent(e);
}

setInterval(update, 1000);
查看更多
太酷不给撩
4楼-- · 2020-04-15 15:50

You need to pass { bubbles: true } as the second argument to new Event( ... ) for the Event to bubble, as per the documentation on MDN, because bubbles defaults to false.

Updated jsfiddle example

查看更多
The star\"
5楼-- · 2020-04-15 15:55

dispatchEvent dispatches your event. Summarizing, that means

When an event is dispatched to an object that participates in a tree (e.g. an element), it can reach event listeners on that object's ancestors too.

First all object's ancestor event listeners whose capture variable is set to true are invoked, in tree order.

Second, object's own event listeners are invoked.

And finally, and only if event's bubbles attribute value is true, object's ancestor event listeners are invoked again, but now in reverse tree order.

Therefore, if the bubbles attribute is not true, the event won't bubble.

You can set the bubbles attribute to true when you create the event with Event:

event = new Event(type [, eventInitDict])

Returns a new event whose type attribute value is set to type. The optional eventInitDict argument allows for setting the bubbles and cancelable attributes via object members of the same name.

查看更多
登录 后发表回答