当Bootstrap模态框关闭时,我如何知道哪个按钮被点击了?

54

这是我的模态框 HTML 代码:

<div class="modal fade" id="delete-file-modal" role="dialog">
    <div class="modal-dialog">
        <div class="modal-content">
            <form class="form-horizontal" method="post" id="delete_file_form">

                <div class="modal-body">
                    Are you sure you want to delete this file?  
                </div>  

                <div class="modal-footer">
                    <button data-dismiss="modal" class="btn btn-danger" name="in_confirm_insert" id="confirm-delete-button">Delete</button>
                    <button data-dismiss="modal" class="btn btn-default" name="in_confirm_insert" id="cancel-delete-button">Cancel</button>
                </div>

            </form>
        </div>
    </div>
</div>

这是我的JavaScript代码:

$('#delete-file-modal').on('hidden.bs.modal', function (e) {

    var delete_button = $(e.target).is("#confirm-delete-button");

    if(delete_button === true) {
        //delete file
        alert("file deleted.");
    } else {
        alert("delete failed.");
    };
});

我需要能够检查当删除文件模态框关闭时是否点击了删除按钮。我的 JavaScript 代码还缺少什么吗?

6个回答

87

选项 #1

hidden.bs.modal 事件的监听器中,event.target 指的是被隐藏的模态框元素,而不是触发了事件的被点击的元素。

如果你想确定是哪个按钮触发了模态框的关闭,一种方法是给模态框内的按钮元素添加事件监听器。然后在按钮事件监听器内部,你可以监听父级 #modal 元素上的 hidden.bs.modal 事件,以确定模态框是否已经关闭。因为 hidden.bs.modal 事件监听器在按钮的 click 事件监听器内部,所以你仍然有一个对触发 click 事件的元素的引用。

此处有示例

$('#delete-file-modal .modal-footer button').on('click', function(event) {
  var $button = $(event.target); // The clicked button

  $(this).closest('.modal').one('hidden.bs.modal', function() {
    // Fire if the button element 
    console.log('The button that closed the modal is: ', $button);
  });
});

值得一提的是,.one() 方法仅在每次连接事件时触发一次(这正是我们想要的)。否则,如果您使用.on().click()连接事件,则事件可能会多次触发,因为每次重新连接click事件侦听器时都会重新连接它。


选项#2

根据相关的Bootstrap文档show.bs.modal/shown.bs.modal事件附带有一个relatedTarget属性。

如果是由单击引起的,则单击的元素可作为事件的relatedTarget属性可用。

因此,您可以通过在模态显示事件侦听器内访问event.relatedTarget来确定触发模态打开事件的元素:

示例在此处

$('#delete-file-modal').on('show.bs.modal', function (event) {
    console.log(event.relatedTarget);
});

请记住,relatedTarget属性仅与模态显示事件相关联。如果它们能够具有类似于hide.bs.modal / hidden.bs.modal事件关联的属性将会很好。截至撰写本文时,目前没有这样的属性。


选项#3

正如Andrew在评论中所指出的那样,您还可以通过访问document.activeElement来检查页面上哪个元素具有焦点。

在下面的代码段中,向模态元素附加了一个事件侦听器,用于显示和隐藏事件。当触发事件时,将进行检查,以查看当前聚焦的元素是否具有[data-toggle][data-dismiss]属性(这意味着它实际上触发了事件)。

示例在此

$('#delete-file-modal').on('hide.bs.modal show.bs.modal', function(event) {
  var $activeElement = $(document.activeElement);
  
  if ($activeElement.is('[data-toggle], [data-dismiss]')) {
    console.log($activeElement);
  }
});

如果您正在同时监听显示/隐藏事件(例如上面的示例),并且想区分这些事件,您可以检查event.type

此处有示例

$('#delete-file-modal').on('hide.bs.modal show.bs.modal', function(event) {
  var $activeElement = $(document.activeElement);
  
  if ($activeElement.is('[data-toggle], [data-dismiss]')) {
    if (event.type === 'hide') {
      // Do something with the button that closed the modal
      console.log('The button that closed the modal is: ', $activeElement);
    }
    
    if (event.type === 'show') {
      // Do something with the button that opened the modal
      console.log('The button that opened the modal is: ', $activeElement);
    }
  }
});

1
谢谢您提供的示例,它完美地运行了。但是我需要在模态框关闭后检查按钮是否被点击。这可能吗? - Nomad
1
我正在使用jQuery 3,e.relatedTarget 显示 undefined。 - elquimista
1
这也可以运行: $('#myModal').on('hide.bs.modal', function (e) { var tmpid = $(document.activeElement).attr('id'); alert(tmpid); }); 除非你给它分配一个ID,否则它不会获取模态框上的“X”.... - Andrew
选项#3很好,但它有一个缺点:手动调用.hide()也会被视为按下Escape键(因为document.activeElement被设置为body)。 - Jan Drábek
1
选项#3中的小提琴在Firefox 57或Safari 10.1.2中不会显示警告。这是过时了吗?但它在Chrome中可以工作。 - robsch
显示剩余4条评论

9
这也可以运行:
$('#myModal').on('hide.bs.modal', function (e) { 
var tmpid = $(document.activeElement).attr('id'); alert(tmpid); 
}); 

如果不给模态框一个id,它就无法获取'X'的id。将返回触发关闭模态框元素的id...


1
您可能还想检查$(document.activeElement).hasClass('btn')以确保它是按钮推送,而不是其他操作。以下是我为什么要这样做的原因。我在同一“您确定吗?”对话框中使用了报名和取消提示。所以,我在显示的按钮上有相同的 id 。因此,我必须检查按钮的 .text() 属性,然后使用.indexOf()。但是,如果有人点击背景或按下 escape 键,则我的 if/then 条件将显示错误的结果。这就是为什么现在我使用.hasClass('btn') 进行检查的原因。 - Volomike
1
简洁明了,我喜欢它!请注意,这将在 hide.bs.modal 上起作用,但不会在 hidden.bs.modal 上起作用。后者始终会显示活动元素为 body,这是有道理的,因为模态框已从 DOM 中删除。 - Nick K9
这是最好的!它不仅可以解决我目前的问题,还将定义我对Bootstrap模态框的未来使用。 - Dejan Dozet
截至2022年12月,在Safari中似乎无法正常工作。但在Chrome和Firefox中可以正常工作。 - Craig Jacobs

2

在扩展@JoshCrozier的答案时:

如果他们与hide.bs.modal / hidden.bs.modal事件相关联具有类似属性,那将是很好的。截至撰写本文,目前还没有


这将模拟类似的行为,将单击的按钮作为相关目标附加到后续侦听器:

$( '.modal-footer .btn[data-dismiss="modal"]' ).on( 'click', function() {
    var target = this

    $( target ).closest( '.modal' )
        .one( 'hide.bs.modal hidden.bs.modal', function( event ) {
            event.relatedTarget = target
        } )
} )

选择器和监听器可以根据模态框在项目中的使用情况进行进一步优化。例如:如果您知道不会使用 hide.bs.modal,则可以直接修改 hidden.bs.modal 的事件。请保留HTML标签。

这种方法没有考虑到用户点击 X 按钮的情况,该按钮位于 .modal-header 而不是 .modal-footer - reformed

1

@JoshCrozier的答案很好也很有用,但有时我们需要在模态框关闭后确定触发模态框打开/关闭的元素。(@Nomad在下面的评论中提到了这一点)。

有时候我们还需要确定在 bodyheader 中哪个链接或按钮触发了模态框的关闭(而不仅仅是 footer 中的按钮)。

然后我写了这个解决方案来混合 @JoshCrozier@Katia 的答案,并改进最终的解决方案:

将此部分添加到您网页的脚本中:

$('body').on('click','.modal .dismiss-modal', function() {
    var closeRelatedTarget = this;
    var $modal = $(closeRelatedTarget).closest('.modal');
    $modal.one('hide.bs.modal hidden.bs.modal', function(event) {
        $modal.data('closeRelatedTarget',closeRelatedTarget);
    });
    $modal.data('closeRelatedTarget','wait');
    $modal.modal('hide');
});
$('body').on('show.bs.modal','.modal', function(event){
    $(this).data('closeRelatedTarget','anElement');
    $(this).data('showRelatedTarget',event.relatedTarget);
});

现在可以使用简单的事件处理程序轻松使用它,或获取目标元素:

● 在 showshown 上确定触发模态框的元素 (一个嵌入式 Bootstrap 功能)

 $('#MyModal').on('show.bs.modal', function (event) {
     console.log(event.relatedTarget);
 });

并且

 $('#MyModal').on('shown.bs.modal', function (event) {
     console.log(event.relatedTarget);
 });

● 确定哪个元素在 hidden 时触发了模态框的关闭。
 $('#BuyModal').on('hidden.bs.modal', function (event) {
      if($(this).data('closeRelatedTarget')=='wait')
      {return;}
 
      console.log($('#MyModal').data('closeRelatedTarget'));
 });

● 确定在模态框关闭后,哪个元素仍然触发了模态框的显示
 console.log($('#MyModal').data('showRelatedTarget'));

● 确定哪个元素触发了模态框关闭,即使模态框已经关闭。
 console.log($('#MyModal').data('closeRelatedTarget'));

注意:使用我的modal-dismiss类代替data-dismiss="modal"属性,将其应用于模态框中的每个元素,您可以关闭模态框并确定它(不要同时使用modal-dismiss类和data-dismiss="modal")。
示例:<a href="/more_info.html" class="dismiss-modal">更多信息</a> 为什么?因为data-dismiss="modal"会在我们设置closeRelatedTarget之前关闭模态框并触发隐藏和隐藏。

1

编辑:这里提供一种适用于BOOTSTRAP 4+的解决方案,可以根据需要适配其他版本,包括v5。如果需要,可能对某些人有用。

<div class="modal-footer">
    <button type="button" class="btn btn-secondary" data-dismiss="modal">Annuler</button>
    <button type="button" class="btn btn-primary" data-dismiss="modal">Valider</button>
</div>

$('#prompt_modal').on('shown.bs.modal', function (event) {
    let buttons = this.querySelectorAll('.btn'); // or others selectors
    buttons.forEach(btn => {
        btn.onclick = () => {
            console.log(btn);
            // do something with btn (textCOntent, dataset, classlist, others) 
            // to detect clicked...
        }
    })
})

但这不是纯JS解决方案吧?这是 JQuery。 - Siddharth Bhansali
@SiddharthBhansali 确实如此! 事实上,“(在引导调用函数中)”是指除了引导函数调用本身之外的内容。但我会将其删除... 可以说,使用v5是可能的... - Jean Gorene

1
我们在想得太多了。这只是一个标准的按钮处理程序。data-dismiss="modal"将使对话框消失,而我们仍然知道我们感兴趣的按钮被点击了。
$('#delete-file-modal').on('click','#delete-file-modal #confirm-delete-button', function (e) {
  e.preventDefault();
  console.log('confirmed delete');
  return false;
});

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