Twitter Bootstrap.为什么模态事件在JQuery中工作但在纯JS中不起作用?

dug*_*gla 21 javascript jquery twitter-bootstrap-3

Twitter Bootstrap模式对话框有一组可用于回调的事件.

这是jQuery中的一个例子:

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

        console.log("hidden.bs.modal");
    });
Run Code Online (Sandbox Code Playgroud)

但是,当我将此方法转录为JS时,事件'hidden.bs.modal'不起作用.使用'click'确实有效:

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

        console.log("hidden.bs.modal");
    }, false);
Run Code Online (Sandbox Code Playgroud)

这些Bootstrap事件只能用于jQuery吗?为什么?

谢谢,
道格

Ada*_*eld 26

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

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

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

(第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');
Run Code Online (Sandbox Code Playgroud)

DEMO

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

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

虽然我不推荐它,但你可以通过对bootstraps代码进行少量更改来解决这个问题.你只需要确保首先附加下面的函数(或者你将有两次触发器).

$(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);
    }
});
Run Code Online (Sandbox Code Playgroud)

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

that.$element.trigger('hidden.bs.modal', true)
Run Code Online (Sandbox Code Playgroud)

这是因为你知道它被触发而不是你自己解雇的事件.请记住,我没有尝试过使用模态的代码.虽然它在click下面的演示中确实可以正常工作,但它可能会或可能不会像模式那样工作.

DEMO

  • 老兄,那是史诗般的.我是一个iOS开发人员,所以我的思想是适当的.对于这个项目,我必须尽可能使用纯JS.什么是纯粹的JS等同于你精彩的论文?干杯. (3认同)

Tom*_*Tom 6

本机 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);
Run Code Online (Sandbox Code Playgroud)

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