Twitter Bootstrap / jQuery - 如何暂时阻止模态框被关闭?

35

我正在使用Twitter Bootstrap的模态框,默认选项为您可以单击背景或按[Esc]键关闭模态框。

但是,当我在模态框中启动ajax操作时,我想禁用任何关闭模态框的方式。因此,我禁用了按钮并隐藏了模态框的关闭按钮,但我无法弄清楚如何禁用背景和[Esc]键。

我尝试过:

$('#myModal').modal({
    backdrop: 'static',
    keyboard: false
});

但是这似乎无法实时工作。

一旦ajax操作完成,我还需要重新启用背景和键盘。

6个回答

17

注意:此解决方案针对的是 twitter bootstrap 2.x。请查看下面的答案了解与 bootstrap 3 的差异。


不修改原始源代码即可扩展 bootstrap 模态框功能。

感谢 @David 及其在如何扩展 Twitter Bootstrap 插件中的建议,我终于让它工作了。这是他解决方案的稍微修改版本,加入了模态框“锁定”。我将其发布为额外的答案,因为我认为它可能成为其他像我一样苦苦挣扎于此问题的人的起点。

// save the original function object
var _superModal = $.fn.modal;

// add locked as a new option
$.extend( _superModal.defaults, {
    locked: false
});

// create a new constructor
var Modal = function(element, options) {
    _superModal.Constructor.apply( this, arguments )
}

// extend prototype and add a super function
Modal.prototype = $.extend({}, _superModal.Constructor.prototype, {
    constructor: Modal

    , _super: function() {
        var args = $.makeArray(arguments)
        // call bootstrap core
        _superModal.Constructor.prototype[args.shift()].apply(this, args)
    }

    , lock : function() {
        this.options.locked = true
    }

    , unlock : function() {
        this.options.locked = false
    }

    , hide: function() {
        if (this.options.locked) return
        this._super('hide')
    }
});

// override the old initialization with the new constructor
$.fn.modal = $.extend(function(option) {
    var args = $.makeArray(arguments),
    option = args.shift()

    // this is executed everytime element.modal() is called
    return this.each(function() {
        var $this = $(this)
        var data = $this.data('modal'),
            options = $.extend({}, _superModal.defaults, $this.data(), typeof option == 'object' && option)

        if (!data) {
            $this.data('modal', (data = new Modal(this, options)))
        }
        if (typeof option == 'string') {
            data[option].apply( data, args )
        }
    });
}, $.fn.modal);

使用这种技术,不需要修改bootstrap.js,而且相同的功能可以更轻松地在bootstrap项目之间共享。该方法适用于所有其他的bootstrap插件。目前只尝试了按钮插件,但我看不出为什么不能。

可见工作示例 -> http://jsfiddle.net/Sz7ZS/


应用此方法后,背景(灰色背景)似乎消失了。我需要手动使用$('#thisModal').modal({backdrop: true});来使用它。这是一个错误还是唯一的方法? - Loonb
@TianLoon。已更新答案并通知 Bootstrap 版本,同时提供了一个使用 2.3.2 版本(最为“流行”的 2.x 版本)Bootstrap 的 jsfiddle。在这个 fiddle 中,背景出现了——也许您不小心将它设置为了不透明0、白色或其他某种颜色? - davidkonrad

10

有一个更简单的方法来做到这一点。这个 bootstrap pull 请求解释的更详细。该解决方案禁用所有关闭模态框的方法(键盘、鼠标单击、关闭按钮)。

您只需执行以下操作即可禁用关闭模态框:

$('#myModal').data('bs.modal').isShown = false;

为了再次启用关闭:

$('#myModal').data('bs.modal').isShown = true;

示例

这是一些与jQuery get结合使用的示例代码:

// disable closing the modal
$('#myModal').data('bs.modal').isShown = false;

// Send an HTTP GET request to the server - replace this with getJSON, post or ajax as needed
$.get( "ajax/test.html", function( data ) {
  // enable closing the modal
  $('#myModal').data('bs.modal').isShown = true;

  // Do something with the data
  $( ".result" ).html( data );
});

9
您不是唯一一个需要这个功能的人。我认为Bootstrap有时过于“极简主义”,背后的人们认为很多工作应该在“实现层”中完成,但当Bootstrap jQuery插件本身使其不可能时,这是没有用的!
您必须自己实现功能,像这样:
在bootstrap.js v2.1.1中,模态框从第61行开始。
在Modal.prototype中,添加两个函数lock和unlock,所以它看起来像这样(我只展示了modal.prototype的开头,因为它是太多代码)。
  Modal.prototype = {

      constructor: Modal

      //add this function
    , lock: function () {
        this.options.locked = true
      }

      //add this function
    , unlock: function () {
        this.options.locked = false
      }

    , toggle: function () {
    ... 
    ...

接下来,在 Modal.prototype 中找到 hide 函数,并添加一行代码,使其看起来像这样(仅显示 hide 的顶部)

, hide: function (e) {
    e && e.preventDefault()

    var that = this

    //add this line
    if (that.options.locked) return

    e = $.Event('hide')
    ...
    ...

最后,将$.fn.modal.defaults修改为:
  $.fn.modal.defaults = {
      backdrop: true
    , keyboard: true
    , show: true
    , locked: false //this line is added
  }

现在你的bootstrap模态框具备即时锁定/解锁功能,可以在重要时刻防止用户关闭模态框。

例子 :

这是来自 http://twitter.github.com/bootstrap/javascript.html#modals 的“Live Demo”修改版。

<!-- Button to trigger modal -->
<a href="#myModal" role="button" class="btn" data-toggle="modal">Launch demo modal</a>

<!-- Modal -->
<div id="myModal" class="modal hide fade" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
  <div class="modal-header">
    <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
    <h3 id="myModalLabel">Modal header</h3>
  </div>
  <div class="modal-body">
    <p>One fine body…</p>
  </div>
  <div class="modal-footer">
    <button class="btn" data-dismiss="modal" aria-hidden="true">Close</button>
    <button class="btn btn-primary" onclick="$('#myModal').modal('lock');">lock</button>
    <button class="btn btn-primary" onclick="$('#myModal').modal('unlock');">unLock</button>
  </div>
</div>
<script type="text/javascript">

我已经插入了两个按钮,“锁定”和“解锁”——当点击时,它们会将模态框设置为锁定或正常模式(与其初始化的设置相同)。
在您的情况下,“编辑”,您只需在执行ajax时调用lock/onlock函数:
$("myModal").modal('lock');
$.ajax({
    url: url,
    ...
    ...
    , success(html) {
       ...
       ...
       $("#myModal").modal('unlock');
    }
});

这个很好,但是你能否通过扩展核心Bootstrap代码来实现它,而不是修改它? - BadHorsie
是的,终于搞定了 :) 多亏了 @david 和你。 - davidkonrad

9

您可以创建一个名为isBlocked的变量,当进行AJAX调用时将其设置为true,然后可以在bootsrap模态框隐藏事件中检查它:

$('#myModal').on('hide.bs.modal', function (e) {
      //Prevent modal from closing is isBlocked is true
      if(isBlocked) return e.preventDefault();
})

我认为这种方法比扩展Bootsrap更容易,希望能对某些人有所帮助:D


1
这绝对是实现这个的最干净的方法。+1 - con

5
感谢@davidkonrad为此工作所做的贡献。我也试图实现这个功能,但似乎在bootstrap 3中有些变化。现在,不再是:

_superModal.defaults

而是附加到构造函数上,因此您必须执行:

_superModal.Constructor.DEFAULTS

此外,构造函数已更改,这意味着我必须复制并修改它,这不是最理想的。相反,我提出了以下代码,可以正常工作,并且不会复制构造函数,如果bootstrap未来发生更改,应该更加可靠。请看一下:

// save the original function object
var _superModal = $.fn.modal;

// add locked as a new option
$.extend( _superModal.Constructor.DEFAULTS, {
    locked: false
});

// capture the original hide
var _hide = _superModal.Constructor.prototype.hide;
// console.log('HIDE:', _hide);

// add the lock, unlock and override the hide of modal
$.extend(_superModal.Constructor.prototype, {
    // locks the dialog so that it cannot be hidden
    lock: function() {
        // console.log('lock called');
        // console.log('OPTIONS',this.options);
        this.options.locked = true;
    }
    // unlocks the dialog so that it can be hidden by 'esc' or clicking on the backdrop (if not static)
    ,unlock: function() {
        // console.log('unlock called');
        this.options.locked = false;
    }
    // override the original hide so that the original is only called if the modal is unlocked
    ,hide: function() {
        // console.log('hide called');
        if (this.options.locked) return;

        _hide.apply(this, arguments);
    }
});

为了锁定模态框:

$('#dlg').modal('lock');

为了解锁:

$('#dlg').modal('unlock');

太好了!

这对我似乎不起作用;当表单正在提交时,它确实阻止模态框在我点击其外部时关闭,但是一旦表单被提交并且我调用.modal("unlock") - 模态框将隐藏... 我没有调用 .modal("hide"),只有解锁。不确定如何可能。有什么想法吗?谢谢 - user429620
1
你正在使用哪个版本的Bootstrap? - ragamufin
非常感谢您。 - Ezequiel Villarreal

1

我更新了这个很棒的脚本,使其与Bootstrap 4兼容。

var _superModal = $.fn.modal;

    $.extend(_superModal.Constructor.Default, {
        locked: false
    });

    var _hide = _superModal.Constructor.prototype.hide;

    $.extend(_superModal.Constructor.prototype, {
        lock: function () {
            this._config.locked = true;
        },
        unlock: function () {
            this._config.locked = false;
        },
        hide: function () {
            if (this._config.locked) return;

            _hide.apply(this, arguments);
        }
    });

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接