Make (possibly dynamically loaded) element clickable via JavaScript, but give precedence to links contained within

为君一笑 提交于 2020-02-25 07:25:08

问题


I am adding a custom data attribute data-js-href to various HTML elements, and these elements should behave just like a link when clicked. If a link within such an element is clicked, the link should take precedence and the data-js-href functionality should be ignored, though. Furthermore, the solution also needs to work with elements that are dynamically added at a later time.

So far, I have come up with the following solution. It basically checks if the click was performed on a link, or any child element of a link (think <a href='…'><img src='…' alt='…' /></a>).

// Make all elements with a `data-js-href` attribute clickable
$$('body').addEvent('click:relay([data-js-href])',
                    function(event, clicked) {
    var link = clicked.get('data-js-href');
    if (link && !event.target.match('a')) {
        var parents = event.target.getParents();
        for (var i = 0; i < parents.length && parents[i] != clicked; i++) {
            if (parents[i].match('a')) {
                return;
            }
        }
        document.location.href = link;
    }
});

It works, but it feels very clumsy, and I think that there has to be a more elegant solution. I tried something along the lines of

$$('body').addEvent('click:relay([data-js-href] a)',
                    function(event, clicked) {
    event.stopPropagation();
}

but to no avail. (I littered the code with some console.log() messages to verify the behavior.) Any idea is welcome.


回答1:


you can do this with 2 delegated events - no reverse lookups and it's cheap as they will share the same event. the downside is, it is the same event so it will fire for both and there's no stopping it via the event methods (already bubbled, it's a single event that stacks up multiple pseudo event callbacks and executes them in order--the event has stopped but the callbacks continue) That's perhaps an inconsistency in mootools event vs delegation implementation but it's a subject of another issue.

Workarounds for now can be:

to have the 2 event handlers communicate through each other. It will scale and work with any new els added.

to add the delegators on 2 different elements. eg. document.body and #mainWrap.

http://jsfiddle.net/dimitar/J59PD/4/

var showURL = function(howLong) {
    // debug.
    return function() {
        console.log(window.location.href);
    }.delay(howLong || 1000);
};

document.id(document.body).addEvents({
    "click:relay([data-js-href] a))": function(e) {
        // performance on lookup for repeat clicks.
        var parent = this.retrieve("parent");
        if (!parent) {
            parent = this.getParent("[data-js-href]");
            this.store("parent", parent);
        }
        // communicate it's a dummy event to parent delegator.
        parent.store("linkEvent", e);
        // let it bubble...
    },
    "click:relay([data-js-href])": function(e) {
        // show where we have gone.
        showURL(1500);
        if (this.retrieve("linkEvent")) {
            this.eliminate("linkEvent");
            return;
        }
        var prop = this.get("data-js-href");
        if (prop)
            window.location.href = prop;


    }
});

Discussed this with Ibolmo and Keeto from the mootools team on IRC as well when my initial attempt failed to work and both callbacks fired despite the event.stop: http://jsfiddle.net/dimitar/J59PD/

As a result, there was briefly a ticket open on the mootools github issues: https://github.com/mootools/mootools-core/issues/2105 but it then went into a discussion of what the right thing to do from the library standpoint is and how viable it is to pursue changing the way things work so...



来源:https://stackoverflow.com/questions/7759861/make-possibly-dynamically-loaded-element-clickable-via-javascript-but-give-pr

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!