【问题标题】:Twitter Bootstrap / jQuery - How to temporarily prevent the modal from being closed?Twitter Bootstrap / jQuery - 如何暂时防止模式被关闭?
【发布时间】:2012-11-05 11:35:33
【问题描述】:

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

但是,当我在模式中启动 ajax 操作时,我想禁止模式以任何方式关闭。所以我禁用按钮并隐藏模式的关闭按钮,但我不知道如何禁用背景和 [Esc] 键。

我试过了:

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

但这似乎无法即时运行。

我还需要在 ajax 操作完成后重新启用背景和键盘。

【问题讨论】:

    标签: javascript jquery twitter-bootstrap modal-dialog twitter-bootstrap-2


    【解决方案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);
            }
        });
    

    【讨论】:

      【解决方案2】:

      您不是唯一缺少该功能的人。我觉得bootstrap有时候太“简约”,后面的人有很多想法应该在“实现层”做,但是当bootstrap jQuery插件本身无法实现时,它就没有用了!

      你必须自己实现这个功能,像这样

      bootstrap.js v2.1.1 modal 中从第61行开始。

      Modal.prototype中,添加两个函数,lockunlock,看起来是这样的(我这里只显示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: 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
        }
      

      现在您的引导模式中具有即时锁定/解锁功能,可防止用户在关键时刻关闭模式。

      示例

      这是来自http://twitter.github.com/bootstrap/javascript.html#modals的“现场演示”的修改版本

      <!-- 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代码而不是修改它来实现它吗?
      • 是的,终于弄明白了 :) 感谢@david,感谢你。
      【解决方案3】:

      您可以创建一个变量 isBlocked,您可以在执行 AJAX 调用时将其设置为 true,然后您可以通过这种方式在 bootsrap modal hide 事件中检查它:

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

      我认为这种方式比扩展 Bootsrap 更容易,希望它可以帮助某人:D

      【讨论】:

      • 绝对是实现这一目标的最干净的方法。 +1
      【解决方案4】:

      有一种更简单的方法可以做到这一点。 This bootstrap pull request 解释了更多。该解决方案禁用所有关闭模态的方法(键盘、鼠标单击、关闭按钮)。

      禁用关闭模式所需要做的就是:

      $('#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 );
      });
      

      【讨论】:

        【解决方案5】:

        注意:此解决方案针对twitter bootstrap 2.x!请参阅this answer(就在下方)了解根据引导程序 3 的差异。


        扩展引导模式功能而不修改原始源。

        感谢@David 和他在How to Extend Twitter Bootstrap Plugin 的建议,我终于让它工作了。这是他的解决方案的略微修改版本,添加了模态“锁定”。我将其作为附加答案发布,因为我认为这可能是其他像我一样在这个问题上苦苦挣扎的人的起点。

        // 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 项目之间共享相同的功能。此方法应该适用于所有其他引导插件。到目前为止只尝试过按钮,但我不明白为什么不应该这样做。

        见工作小提琴 -> http://jsfiddle.net/Sz7ZS/

        【讨论】:

        • 应用此方法后,背景(灰色背景)似乎消失了。我需要手动 $('#thisModal').modal({backdrop: true});使用它。这是一个错误还是这是唯一的方法?
        • @TianLoon。使用 bootstrap 2.3.2(最“流行”的 2.x 版本)更新了关于 bootstrap 版本和jsfiddle 的通知的答案。在小提琴中出现了背景 - 也许你不小心将它设置为不透明 0、白色或其他什么?
        【解决方案6】:

        感谢@davidkonrad 在这方面所做的工作。我也试图实现这一点,似乎引导程序 3 改变了。现在而不是:

        _superModal.defaults

        它现在附加到构造函数,所以你必须这样做

        _superModal.Constructor.DEFAULTS

        构造函数也发生了变化,这意味着我必须复制并修改它,这不太理想。相反,我提出了以下代码,它可以工作并且不会复制构造函数,并且如果引导程序发生变化,应该更加万无一失。试一试:

        // 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"),只解锁。不知道这怎么可能。有任何想法吗?谢谢
        • 你使用的是什么版本的引导程序?
        • 非常感谢。
        猜你喜欢
        • 2014-09-04
        • 2012-04-11
        • 1970-01-01
        • 2012-06-12
        • 1970-01-01
        • 2012-10-09
        • 2023-03-23
        • 2012-03-03
        • 2012-04-04
        相关资源
        最近更新 更多