使(可能是动态加载的)元素通过JavaScript可点击,但优先考虑其中包含的链接

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

本文关键字:链接 包含 JavaScript 动态 加载 元素      更新时间:2023-09-26

我正在向各种HTML元素添加自定义数据属性data-js-href,并且这些元素在单击时应该表现得像链接一样。如果单击这样一个元素中的链接,则该链接应该优先,而data-js-href功能应该被忽略。此外,该解决方案还需要处理稍后动态添加的元素。

到目前为止,我已经提出了以下解决方案。它基本上检查点击是否在链接上执行,或者链接的任何子元素(想想<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;
    }
});

可以工作,但是感觉非常笨拙,我认为必须有一个更优雅的解决方案。我尝试了一些类似

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

,但无济于事。(我在代码中添加了一些console.log()消息来验证这种行为。)

你可以用2个委托事件来做到这一点——没有反向查找,而且成本很低,因为它们将共享同一个事件。缺点是,它是相同的事件,所以它将为两者触发,并且没有通过事件方法停止它(已经冒泡,它是一个单一事件,堆叠多个伪事件回调并按顺序执行它们-事件已经停止,但回调继续)这可能是mootools事件与委托实现中的不一致,但这是另一个问题的主题。

现在的解决方法是:

让两个事件处理程序相互通信。它将扩展和工作与任何新的添加。

在两个不同的元素上添加委托。如。文档。body和#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;

    }
});

在IRC上与mootools团队的Ibolmo和Keeto讨论了这个问题,当我最初的尝试失败时,尽管event.stop: http://jsfiddle.net/dimitar/J59PD/

结果,有一个关于mootools github问题的简短票务:https://github.com/mootools/mootools-core/issues/2105,但它随后进入了一个讨论,从库的角度来看,正确的事情是什么,以及改变事情的工作方式是多么可行……