jQuery UI - закрытие диалогового окна при щелчке за пределами

114

У меня есть диалоговое окно пользовательского интерфейса jQuery, которое отображается при нажатии определенных элементов. Я хотел бы закрыть диалоговое окно, если щелчок происходит где-либо, кроме этих запускающих элементов или самого диалогового окна.

Вот код для открытия диалога:

$(document).ready(function() {
    var $field_hint = $('<div></div>')
        .dialog({
            autoOpen: false,
            minHeight: 50,
            resizable: false,
            width: 375
        });

    $('.hint').click(function() {
        var $hint = $(this);
        $field_hint.html($hint.html());
        $field_hint.dialog('option', 'position', [162, $hint.offset().top + 25]);
        $field_hint.dialog('option', 'title', $hint.siblings('label').html());
        $field_hint.dialog('open');
    });
    /*$(document).click(function() {
        $field_hint.dialog('close');
    });*/
});

Если я раскомментирую последнюю часть, диалог никогда не откроется. Я предполагаю, что это потому, что тот же щелчок, который открывает диалоговое окно, снова закрывает его.


Последнее примечание по рабочему коду
: здесь используется плагин внешних событий jQuery.

$(document).ready(function() {
    // dialog element to .hint
    var $field_hint = $('<div></div>')
            .dialog({
                autoOpen: false,
                minHeight: 0,
                resizable: false,
                width: 376
            })
            .bind('clickoutside', function(e) {
                $target = $(e.target);
                if (!$target.filter('.hint').length
                        && !$target.filter('.hintclickicon').length) {
                    $field_hint.dialog('close');
                }
            });

    // attach dialog element to .hint elements
    $('.hint').click(function() {
        var $hint = $(this);
        $field_hint.html('<div style="max-height: 300px;">' + $hint.html() + '</div>');
        $field_hint.dialog('option', 'position', [$hint.offset().left - 384, $hint.offset().top + 24 - $(document).scrollTop()]);
        $field_hint.dialog('option', 'title', $hint.siblings('label').html());
        $field_hint.dialog('open');
    });

    // trigger .hint dialog with an anchor tag referencing the form element
    $('.hintclickicon').click(function(e) {
        e.preventDefault();
        $($(this).get(0).hash + ' .hint').trigger('click');
    });
});
Сынок
источник

Ответы:

31

Ознакомьтесь с плагином jQuery Outside Events

Позволяет сделать:

$field_hint.bind('clickoutside',function(){
    $field_hint.dialog('close');
});
PetersenDidIt
источник
У меня такое же поведение, поскольку подсказка не отображается при нажатии элементов $ ('. Hint'). Эти элементы находятся «вне» диалога.
Сонни,
Вас интересует только щелчок снаружи, если диалоговое окно открыто. Поэтому связывайте его только после того, как откроете.
PetersenDidIt
3
Я читал в другом месте о фильтрации, основанной на событии, и это решило проблему: groups.google.com/group/jquery-ui/msg/a880d99138e1e80d
Sonny
Диалог повторно используется в документе несколько раз, поэтому у меня должен быть способ отвязать его при закрытии диалога. Я думаю, что фильтрация - более простое решение.
Сонни,
160

Извините, что так долго тянул, но я использовал нижеприведенный. Есть недостатки? См. Функцию открытия ...

$("#popup").dialog(
{
    height: 670,
    width: 680,
    modal: true,
    autoOpen: false,
    close: function(event, ui) { $('#wrap').show(); },
    open: function(event, ui) 
    { 
        $('.ui-widget-overlay').bind('click', function()
        { 
            $("#popup").dialog('close'); 
        }); 
    }
});
stumac85
источник
18
На самом деле это будет работать, только если окно пользовательского интерфейса является модальным.
Очень
37
Очень хорошо. Я просто изменил его на это, поэтому мне не нужно было явно указывать ссылку на идентификатор:$('.ui-widget-overlay').bind('click', function () { $(this).siblings('.ui-dialog').find('.ui-dialog-content').dialog('close'); });
Джеймс МакКормак,
1
Мне нравится этот. Есть ли случай, когда вы не хотите, чтобы это было модально, но все же хотите щелкнуть снаружи, чтобы закрыть? Для меня это не имеет смысла (я предполагаю, что с модальным режимом вы теряете зависание внешних / нижних элементов).
Ник Спейсек,
3
@NickSpacek - когда это не модально, я могу установить фокус на поле, открыть новый диалог и т.д. одним щелчком мыши. В модальном диалоговом окне мне пришлось бы использовать два щелчка: один, чтобы закрыть его, и один, чтобы выполнить следующее действие.
Сонни,
1
Спасибо! Вы также можете воспользоваться динамической динамикой jQuery. $ ('body'). on ('щелкнуть', '.ui-widget-overlay', закрыть);
Куанг Ван
78

Забудьте об использовании другого плагина:

Вот 3 метода закрытия диалогового окна пользовательского интерфейса jquery при нажатии за пределами всплывающего окна:

Если диалоговое окно является модальным / имеет наложение фона: http://jsfiddle.net/jasonday/6FGqN/

jQuery(document).ready(function() {
    jQuery("#dialog").dialog({
        bgiframe: true,
        autoOpen: false,
        height: 100,
        modal: true,
        open: function(){
            jQuery('.ui-widget-overlay').bind('click',function(){
                jQuery('#dialog').dialog('close');
            })
        }
    });
}); 

Если диалог не модальный Метод 1: метод 1: http://jsfiddle.net/jasonday/xpkFf/

 // Close Pop-in If the user clicks anywhere else on the page
                     jQuery('body')
                      .bind(
                       'click',
                       function(e){
                        if(
                         jQuery('#dialog').dialog('isOpen')
                         && !jQuery(e.target).is('.ui-dialog, a')
                         && !jQuery(e.target).closest('.ui-dialog').length
                        ){
                         jQuery('#dialog').dialog('close');
                        }
                       }
                      );

Немодальный диалог, метод 2: http://jsfiddle.net/jasonday/eccKr/

  $(function() {
            $( "#dialog" ).dialog({
                autoOpen: false, 
                minHeight: 100,
                width: 342,
                draggable: true,
                resizable: false,
                modal: false,
                closeText: 'Close',
                  open: function() {
                      closedialog = 1;
                      $(document).bind('click', overlayclickclose);
                  },
                  focus: function() {
                      closedialog = 0;
                  },
                  close: function() {
                      $(document).unbind('click');
                  }



        });

         $('#linkID').click(function() {
            $('#dialog').dialog('open');
            closedialog = 0;
        });

         var closedialog;

          function overlayclickclose() {
              if (closedialog) {
                  $('#dialog').dialog('close');
              }

              //set to one because click on dialog box sets to zero
              closedialog = 1;
          }


  });
Джейсон
источник
2
Большой! Я немного изменил функцию open option для модального диалога, поэтому нет необходимости явно указывать элемент. open : function () { $('.ui-widget-overlay').on('click', function () { $(this).parents("body").find(".ui-dialog-content").dialog("close"); }); }
меридиус
Обратите внимание, что для решения № 2 .is ('. Ui-dialog, a') необходимо изменить на .is ('. Ui-dialog ,whatYouClickOnToOpenTheDialog')
personne3000
@Jason из-за запятой, я думаю, что эта строка на самом деле говорит «не об интерфейсе пользователя или какой-либо ссылке на странице». Если я изменю ссылку «Открыть диалоговое окно» в вашем примере на <span>, диалоговое окно будет закрыто сразу после открытия, поскольку событие окна запускается последним, поэтому я думаю, вам нужно исключить элемент, на который вы нажимаете, чтобы открыть диалог. Я не понимаю, зачем вам ссылаться на ссылки в диалоговом окне?
personne3000
@ personne3000 - на самом деле вы правы насчет контекста, что селектор выбирает оба. Я пытаюсь вспомнить, почему я добавил это, поскольку у меня, должно быть, была конкретная причина, которую я сейчас не помню.
Джейсон
@Jason, чтобы избежать конфликтов с несколькими диалогами, вы можете использовать события с пространством именclick.myNamespace
Кристоф Русси,
17

Просто добавьте этот глобальный скрипт, который закрывает все модальные диалоги, просто щелкая за их пределами.

$(document).ready(function()
{
    $(document.body).on("click", ".ui-widget-overlay", function()
    {
        $.each($(".ui-dialog"), function()
        {
            var $dialog;
            $dialog = $(this).children(".ui-dialog-content");
            if($dialog.dialog("option", "modal"))
            {
                $dialog.dialog("close");
            }
        });
    });;
});
Микеле Локати
источник
Я не использую модальный диалог. Ответ здесь с наибольшим количеством голосов - также для модальных диалогов.
Сонни,
При использовании одного и того же диалогового окна более одного раза на одной странице это единственный способ, поскольку он будет работать только один раз, если вы привяжете его в открытой функции. Спасибо за отличную идею!
MaDaHoPe
вот мой:$(document).on('click', '.ui-widget-overlay', function() { $('#'+$('.ui-dialog-content')[0].id).dialog('close'); });
mr5
10
$(".ui-widget-overlay").click (function () {
    $("#dialog-id").dialog( "close" );
});

Скрипка, показывающая приведенный выше код в действии.

JK.
источник
Я посмотрю на это. Спасибо, Джен!
Сонни,
8

Пришлось сделать две части. Сначала внешний обработчик кликов:

$(document).on('click', function(e){
    if ($(".ui-dialog").length) {
        if (!$(e.target).parents().filter('.ui-dialog').length) {
            $('.ui-dialog-content').dialog('close');
        }
    }
}); 

Это вызывает dialog('close')общий ui-dialog-contentкласс и поэтому закроет все диалоговые окна, если щелчок не произошел в одном из них. Он также будет работать с модальными диалоговыми окнами, поскольку оверлей не является частью .ui-dialogблока.

Проблема в:

  1. Большинство диалогов создаются из-за щелчков вне диалогового окна.
  2. Этот обработчик запускается после того, как эти щелчки создают диалоговое окно и переходят в документ, поэтому он немедленно закрывает их.

Чтобы исправить это, мне пришлось добавить stopPropagation к этим обработчикам кликов:

moreLink.on('click', function (e) {
    listBox.dialog();
    e.stopPropagation(); //Don't trigger the outside click handler
});
Джерф
источник
Это звучит проще, чем решение, которое я использую. Придется попробовать.
Сонни,
Это решение, которое я придумал сам, но мое однострочное:$('body').on('click', '.ui-widget-overlay', function () { $('#myDialog').dialog('close'); });
styfle
5

Этот вопрос немного устарел, но в случае, если кто-то хочет закрыть диалоговое окно, которое НЕ является модальным, когда пользователь где-то щелкает, вы можете использовать его, который я взял из плагина JQuery UI Multiselect . Основное преимущество в том, что клик не «теряется» (если пользователь хочет нажать на ссылку или кнопку, действие будет выполнено).

$myselector.dialog({
            title: "Dialog that closes when user clicks outside",
            modal:false,
            close: function(){
                        $(document).off('mousedown.mydialog');
                    },
            open: function(event, ui) { 
                    var $dialog = $(this).dialog('widget');
                    $(document).on('mousedown.mydialog', function(e) {
                        // Close when user clicks elsewhere
                        if($dialog.dialog('isOpen') && !$.contains($myselector.dialog('widget')[0], e.target)){
                            $myselector.dialog('close');
                        }            
                    });
                }                    
            });
Мелани
источник
Мне пришлось переместиться var $dialog = $(this).dialog('widget');внутрь обработчика событий по щелчку
Стефан Хаберл
1
@Melanie, я думаю, ваше решение более применимо, чем другие. Один парень создал плагин для 'jqui dialog' на основе вашего подхода - js на github
реснянский 01
5

Вы можете сделать это без использования дополнительных плагинов.

var $dialog= $(document.createElement("div")).appendTo(document.body);
    var dialogOverlay;

    $dialog.dialog({
        title: "Your title",
        modal: true,
        resizable: true,
        draggable: false,
        autoOpen: false,
        width: "auto",
        show: "fade",
        hide: "fade",
        open:function(){
            $dialog.dialog('widget').animate({
                width: "+=300", 
                left: "-=150"
            });

//get the last overlay in the dom
            $dialogOverlay = $(".ui-widget-overlay").last();
//remove any event handler bound to it.
            $dialogOverlay.unbind();
            $dialogOverlay.click(function(){
//close the dialog whenever the overlay is clicked.
                $dialog.dialog("close");
            });
        }
    });

Здесь $ dialog - это диалог. По сути, мы получаем последний виджет наложения при каждом открытии этого диалогового окна и привязываем обработчик кликов к этому наложению, чтобы закрыть диалоговое окно $, как при каждом щелчке на наложении.

GuruKay
источник
Я думаю, что это похоже на другие решения для модального диалога. Мой вопрос касался немодальных диалогов.
Сонни
5

нет необходимости в плагине внешних событий ...

просто добавьте обработчик событий в div .ui-widget-overlay:

jQuery(document).on('click', 'body > .ui-widget-overlay', function(){
     jQuery("#ui-dialog-selector-goes-here").dialog("close");
     return false;
});

просто убедитесь, что любой селектор, который вы использовали для диалогового окна jQuery ui, также вызывается, чтобы закрыть его .. т.е. # ui-dialog-selector-go-here

Джонатан Марзулло
источник
Уже предложено несколько решений для закрытия модальных диалогов. Мой диалог не является модальным и поэтому не имеет оверлея.
Сонни
Затем вы просто привязываете событие click к тегу body или оболочке div и используете его в качестве триггера события click вместо модального.
Джонатан Марзулло
Да. По сути, это то, что делает мое решение. Он также должен исключать щелчки в диалоговом окне.
Сонни,
3

При этом не используется пользовательский интерфейс jQuery, но используется jQuery, что может быть полезно для тех, кто по какой-либо причине не использует пользовательский интерфейс jQuery. Сделайте это так:

function showDialog(){
  $('#dialog').show();
  $('*').on('click',function(e){
    $('#zoomer').hide();
  });
}

$(document).ready(function(){

  showDialog();    

});

Итак, как только я показал диалоговое окно, я добавляю обработчик кликов, который ищет только первый щелчок по чему-либо.

Было бы лучше, если бы я мог заставить его игнорировать щелчки по чему-либо в #dialog и его содержимом, но когда я попытался переключить $ ('*') на $ (': not ("# dialog, # dialog *") '), он по-прежнему обнаруживал # диалоговых кликов.

В любом случае, я использовал это исключительно для фото-лайтбокса, так что с этой целью он работал нормально.

Volomike
источник
2

В данном примере (-ах) используется один диалог с идентификатором '#dialog', мне нужно было решение, которое закрывает любой диалог:

$.extend($.ui.dialog.prototype.options, {
    modal: true,
    open: function(object) {
        jQuery('.ui-widget-overlay').bind('click', function() {              
            var id = jQuery(object.target).attr('id');
            jQuery('#'+id).dialog('close');
        })
    }
});

Спасибо моему коллеге Юри Аркестейну за предложение использовать прототип.

Давид ван дер Туйн
источник
2

Это единственный метод, который работал у меня в НЕМОДАЛЬНОМ диалоге.

$(document).mousedown(function(e) {
    var clicked = $(e.target); // get the element clicked
    if (clicked.is('#dlg') || clicked.parents().is('#dlg') || clicked.is('.ui-dialog-titlebar')) {
        return; // click happened within the dialog, do nothing here
    } else { // click was outside the dialog, so close it
        $('#dlg').dialog("close");
    }
});

Вся заслуга принадлежит Axle
Click за пределами немодального диалога, чтобы закрыть

Colin
источник
1

Для тех, кто вас интересует, я создал общий плагин, который позволяет закрыть диалоговое окно, щелкнув за его пределами, будь то модальный или немодальный диалог. Он поддерживает один или несколько диалогов на одной странице.

Дополнительная информация здесь: http://www.coheractio.com/blog/closing-jquery-ui-dialog-widget-when-clicking-outside

Laurent

Laurent
источник
1

Я использую это решение на основе одного из размещенных здесь:

var g_divOpenDialog = null;
function _openDlg(l_d) {

  // http://stackoverflow.com/questions/2554779/jquery-ui-close-dialog-when-clicked-outside
  jQuery('body').bind(
   'click',
   function(e){
    if(
      g_divOpenDialog!=null 
      && !jQuery(e.target).is('.ui-dialog, a')
      && !jQuery(e.target).closest('.ui-dialog').length
    ){
      _closeDlg();
    }
   }
  );

  setTimeout(function() {
    g_divOpenDialog = l_d;
    g_divOpenDialog.dialog();
  }, 500);
}
function _closeDlg() {
  jQuery('body').unbind('click');
  g_divOpenDialog.dialog('close');
  g_divOpenDialog.dialog('destroy');
  g_divOpenDialog = null;
}
Алехо
источник
1

У меня была такая же проблема при создании модального предварительного просмотра на одной странице. После долгих поисков в Google я нашел это очень полезное решение. С помощью события и цели он проверяет, где произошло нажатие, и в зависимости от этого запускает действие или ничего не делает.

Сайт библиотеки фрагментов кода

$('#modal-background').mousedown(function(e) {
var clicked = $(e.target);  
if (clicked.is('#modal-content') || clicked.parents().is('#modal-content')) 
    return; 
} else {  
 $('#modal-background').hide();
}
});
Никола Миркович - Джонни
источник
0

Это просто, на самом деле вам не нужны плагины, просто jquery или вы можете сделать это с помощью простого javascript.

$('#dialog').on('click', function(e){
  e.stopPropagation();
});
$(document.body).on('click', function(e){
  master.hide();
});
Рзасгал
источник
0

Я не думаю, что найти диалоги с использованием $ ('. Any-selector') из всей DOM так здорово.

Пытаться

$('<div />').dialog({
    open: function(event, ui){
        var ins = $(this).dialog('instance');
        var overlay = ins.overlay;
        overlay.off('click').on('click', {$dialog: $(this)}, function(event){
            event.data.$dialog.dialog('close');
        });
    }
});

Вы действительно получаете оверлей из экземпляра диалога, которому он принадлежит, так никогда не пойдет не так.

Плохой парень
источник
Это для модального диалога? Мой OP о немодальном, поэтому наложения нет.
Сонни,
0

С помощью следующего кода вы можете имитировать щелчок по кнопке «закрыть» диалогового окна (измените строку «MY_DIALOG» на имя вашего собственного диалога)

$("div[aria-labelledby='ui-dialog-title-MY_DIALOG'] div.ui-helper-clearfix a.ui-dialog-titlebar-close")[0].click();
perkas
источник
0

Умный код: я использую следующий код, чтобы все оставалось ясным и читаемым. out side body закроет диалоговое окно.

$(document).ready(function () {
   $('body').on('click', '.ui-widget-overlay', closeDialogBox);
});

function closeDialogBox() {
    $('#dialog-message').dialog('close');
}
Фарид Аббас
источник
0

В итоге я использовал этот код, который должен работать с любыми открытыми диалогами на странице, игнорировать щелчки по всплывающим подсказкам, а также очищать ресурсы закрываемого диалога.


        $(document).mousedown(function(e) {
            var clicked = $(e.target); // get the element clicked
            if (clicked.is('.ui-dialog-content, .ui-dialog-titlebar, .ui-tooltip') || clicked.parents().is('.ui-dialog-content, .ui-dialog-titlebar, .ui-tooltip')) {
                return; // click happened within the dialog, do nothing here
            } else { // click was outside the dialog, so close it
                $('.ui-dialog-content').dialog("close");
                $('.ui-dialog-content').dialog("destroy");
                $('.ui-dialog-content').detach();

            }
        });
Кевин Барагона
источник