twitter引导程序。为什么模态事件在 JQuery 中有效,而在纯 JS 中无效?

IT技术 javascript jquery twitter-bootstrap-3
2021-02-24 00:32:25

Twitter Bootstrap 模态对话框有一组可与回调一起使用的事件。

这是 jQuery 中的一个示例:

    $(modalID).on('hidden.bs.modal', function (e) {

        console.log("hidden.bs.modal");
    });

但是,当我将此方法转录到 JS 时,事件'hidden.bs.modal'不起作用。使用“点击”确实有效:

    document.querySelector(modalID).addEventListener('hidden.bs.modal', function(e) {

        console.log("hidden.bs.modal");
    }, false);

这些 Bootstrap 事件是否只能与 jQuery 一起使用?为什么?

谢谢,
道格

2个回答

这背后的原因是因为 Twitter Bootstrap 使用that.$element.trigger('hidden.bs.modal')第 997 行)来触发它的事件。换句话说,它使用.trigger.

现在的jQuery跟踪每个元素的事件处理程序(全部.on.bind.click使用等)._data这是因为没有任何其他方法可以获取绑定(使用.addEventListener)到元素的事件处理程序所以触发器方法实际上只是从._data(element, 'events')&._data(element, 'handle')作为一个数组获取设置的事件侦听器/处理程序并运行它们中的每一个。

handle = ( jQuery._data( cur, "events" ) || {} )[ event.type ] && jQuery._data( cur, "handle" );
if ( handle ) {
    handle.apply( cur, data );
}

第 4548 行

这意味着无论什么上下文,如果一个事件是通过.addEventListener绑定的,它就不会使用.trigger. 这是一个例子。仅在加载jquery时记录(由 触发.trigger)。a但是,如果您单击该元素,两者都会运行。

$('a')[0].addEventListener('click', function(){console.log('addlistener');}, false);

$('a').on('click', function(){
    console.log('jquery');
});

$('a').trigger('click');

演示

或者,您可以使用fireEvent(ie) & dispatchEvent(non-ie)在 javascript 中的元素上触发事件我不一定理解或知道 jQuery.trigger不这样做的原因,但他们可能有也可能没有。经过更多的研究,我发现他们不这样做,因为一些较旧的浏览器每个事件只支持 1 个事件处理程序。

一般来说,我们没有尝试实现仅适用于某些浏览器(和某些事件)而不是所有浏览器的功能,因为有人会立即提交无法正常工作的错误。

虽然我不推荐它,但您可以通过对引导程序代码进行最少的更改来解决此问题。您只需要确保首先附加下面的函数(否则您将有听众触发两次)。

$(modalID).on('hidden.bs.modal', function (e, triggered) {
    var event; // The custom event that will be created

    if(!triggered){
        return false;
    }

    e.preventDefault();
    e.stopImmediatePropagation();

    if (document.createEvent) {
        event = document.createEvent("HTMLEvents");
        event.initEvent("hidden.bs.modal", true, true);
    } else {
        event = document.createEventObject();
        event.eventType = "hidden.bs.modal";
    }

    event.eventName = "hidden.bs.modal";

    if (document.createEvent) {
        this.dispatchEvent(event);
    } else {
        this.fireEvent("on" + event.eventType, event);
    }
});

最后将 Twitter Bootstrap 行从上面更改为:

that.$element.trigger('hidden.bs.modal', true)

这是为了让您知道它是被触发的,而不是您自己触发的事件。请记住,我还没有用模态尝试过这段代码。尽管它在click下面演示中运行良好,但它可能会或可能不会在模态中按预期工作。

演示

伙计,那是史诗般的。我是 JS 的 iOS 开发新手,所以我的想法很合适。对于这个项目,我必须尽可能使用纯 JS。什么是纯JS相当于你的精彩论文?干杯。
2021-04-28 00:32:25

原生 Javascript 解决方案。这是我在没有 JQuery 的情况下的做法。

//my code ----------------------------------------
export const ModalHiddenEventListener = (el, fn, owner) => {
    const opts = {
        attributeFilter: ['style']
    },
    mo = new MutationObserver(mutations => {
        for (let mutation of mutations) {
            if (mutation.type === 'attributes' 
            && mutation.attributeName ==='style' 
            && mutation.target.getAttribute('style') === 'display: none;') {
                mo.disconnect();
                fn({
                    owner: owner,
                    element: mutation.target
                });
            }
        }
    });
    mo.observe(el, opts);
};
//your code with Bootstrap modal id='modal'------- 
const el = document.getElementById('modal'),
      onHide = e => {
          console.log(`hidden.bs.modal`); 
      };
ModalHiddenEventListener(el, onHide, this);

兼容性:https : //developer.mozilla.org/en-US/docs/Web/API/MutationObserver/observe#Browser_compatibility

我完全确定您是 JS Vanilla 大师。祝贺这个解决方案。
2021-05-03 00:32:25