Запретить диалогу jQuery UI устанавливать фокус на первое текстовое поле


156

Я настроил модальное диалоговое окно jQuery UI, которое отображается, когда пользователь нажимает на ссылку. В этом теге div диалогового окна есть два текстовых поля (для краткости я показываю только код 1), и оно заменено на текстовое поле jQuery UI DatePicker, которое реагирует на фокус.

Проблема заключается в том, что диалоговое окно jQuery UI («open») каким-то образом вызывает фокусировку первого текстового поля, а затем немедленно запускает календарь DatePicker.

Поэтому я ищу способ предотвратить фокусировку автоматически.

<div><a id="lnkAddReservation" href="#">Add reservation</a></div>

<div id="divNewReservation" style="display:none" title="Add reservation">
    <table>
        <tr>
            <th><asp:Label AssociatedControlID="txtStartDate" runat="server" Text="Start date" /></th>
            <td>
                <asp:TextBox ID="txtStartDate" runat="server" CssClass="datepicker" />
            </td>
        </tr>
    </table>

    <div>
        <asp:Button ID="btnAddReservation" runat="server" OnClick="btnAddReservation_Click" Text="Add reservation" />
    </div>
</div>

<script type="text/javascript">
    $(document).ready(function() {
        var dlg = $('#divNewReservation');
        $('.datepicker').datepicker({ duration: '' });
        dlg.dialog({ autoOpen:false, modal: true, width:400 });
        $('#lnkAddReservation').click(function() { dlg.dialog('open'); return false; });
        dlg.parent().appendTo(jQuery("form:first"));
    });
</script>

это установит фокус даже на изображение! как для обычных тегов <img>, так и для <input type = image>
Simon_Weaver

Ответы:


78

jQuery UI 1.10.0 Список изменений показывает билет 4731 как исправленный.

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

Расширение автофокуса, начиная с [автофокус], затем: содержимое с вкладками, затем панель кнопок, затем кнопка закрытия, затем диалоговое окно

Итак, пометьте элемент autofocusатрибутом, и именно этот элемент должен получить фокус:

<input autofocus>

В документации объясняется логика фокуса (только под оглавлением, под заголовком «Фокус»):

При открытии диалога фокус автоматически перемещается на первый элемент, который соответствует следующему:

  1. Первый элемент в диалоге с autofocusатрибутом
  2. Первый :tabbableэлемент в содержании диалога
  3. Первый :tabbableэлемент в панели кнопок диалога
  4. Кнопка закрытия диалога
  5. Сам диалог

Для чего нужен понижающий голос? Если это произошло из-за того, что я указал версию 1.9 в качестве исправленной версии, я обновил версию до 1.10, чтобы соответствовать заявке.
Slolife

1
Я просматриваю документацию jQuery-ui 1.10 для Dialog и не вижу ее. Я искал "focusSelector" в API, и его там нет.
Пол Томблин

3
Установка фокуса на любой элемент, находящийся за пределами экрана, прокручивает окно вверх или вниз к этому элементу, и это происходит всякий раз, когда окно получает фокус, а не только при открытии диалога. Если я использую Firebug для «проверки элемента», а затем щелкаю обратно в окне документа, мое окно прокручивается вверх или вниз до того элемента, на котором сфокусирован jQuery-UI. Вопрос не в том, как выбрать, какой элемент получает фокус, а в том, как предотвратить фокус. Выбор другого элемента для фокусировки не решит проблему.
Владимир Корнеа

4
Идея, что jQuery UI считает это «исправленным», безумна. Исправление для удаления любой автофокусировки логики в целом. Я просил вас открыть диалог, а не фокусироваться на вводе. Так раздражает.
AJB

2
Кстати, я добавил вход w / type = "hidden" над первым входом и добавил к нему атрибут автофокуса. Это не означает, что вы думаете, это означает, но это работает для решения этой проблемы.
Jinglesthula

77

Добавьте скрытый диапазон над ним, используйте ui-helper-hidden-available, чтобы сделать его скрытым путем абсолютного позиционирования. Я знаю, что у вас есть этот класс, потому что вы используете диалог из jquery-ui, а он в jquery-ui.

<span class="ui-helper-hidden-accessible"><input type="text"/></span>

1
Отличная работа вокруг. Не требуется JS, не меняет макет, и JQuery UI поддерживает его изначально.
steampowered

Согласитесь, отличная работа вокруг. Также приятно узнать о скрыто-доступном классе! Спасибо!!
user1055761

4
Это создает проблемы для людей, использующих вспомогательные технологии (например, программы для чтения с экрана)
rink.attendant.6

1
@ rink.attendant.6 какие проблемы?
Oxfn

изумительное решение
Педро Коэльо

63

В jQuery UI> = 1.10.2 вы можете заменить _focusTabbableметод-прототип функцией плацебо:

$.ui.dialog.prototype._focusTabbable = $.noop;

скрипка

Это повлияет на все dialogs на странице без необходимости редактировать каждый вручную.

Оригинальная функция не делает ничего, кроме установки фокуса на первый элемент с autofocusатрибутом / tabbableelement / или возврата к самому диалогу. Поскольку его использование - просто установка фокуса на элемент, не должно быть проблем с заменой его на a noop.


7
Часы и часы и часы и часы горели на этом. Мой клиент благодарит вас.
Ламарант

1
Это должен быть ответ!
briansol

2 дня искал это решение ... больше ничего не получалось ... Большое спасибо!
Легионар

1
Предупреждение: когда всплывает диалоговое окно, нажатие клавиши Escape не закроет диалоговое окно (пока вы не сфокусируете диалоговое окно).
Роберт

1
@ Роберт, вместо того, чтобы заменить его $.noop, замените его функцией, которая записывает активный диалог, затем зарегистрируйте обработчик события глобального ключа, который перехватывает ESCи закрывает «активный» диалог, если он есть.
Перкинс

28

Начиная с jQuery UI 1.10.0, вы можете выбирать, на какой элемент ввода фокусироваться, используя автофокусировку HTML5-атрибута .

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

<input type="hidden" autofocus="autofocus" />

Это было проверено в Chrome, Firefox и Internet Explorer (все последние версии) 7 февраля 2013 г.

http://jqueryui.com/upgrade-guide/1.10/#added-ability-to-specify-which-element-to-focus-on-open


27

Я нашел следующий код функции диалога JQuery UI для открытия.

c([]).add(d.find(".ui-dialog-content :tabbable:first")).add(d.find(".ui-dialog-buttonpane :tabbable:first")).add(d).filter(":first").focus();

Вы можете либо обойти поведение jQuery, либо изменить поведение.

tabindex -1 работает как обходной путь.


1
Разве tabindex = -1 не помешает мне перейти к текстовому полю?
Slolife

2
Спасибо за исследование. Теперь я знаю, что это действительно код, который делает это. Я мог бы предложить команде jQuery UI добавить опцию, чтобы отключить эту автофокусировку.
Slolife

3
@slolife - Извините, что воскресил этот действительно старый поток, но в этом билете сказано, что исправление ( focusSelectorопция) должно быть в jQueryUI 1.8, а сейчас мы находимся на 1.8.13, и я не вижу его в документации по диалогу jQueryUI , Что случилось с этим?
Том Хэмминг

Неважно. Я видел, как «Milestone изменился с TBD до 1.8» в истории изменений, и не заметил, что на самом деле он говорит 1.9 вверху.
Том Хэмминг

У меня похожая проблема, мой обходной путь описан здесь - stackoverflow.com/a/12250193/80002
отметка

15

Просто понял это во время игры.

Я нашел с этими решениями, чтобы удалить фокус, заставил ESCключ перестать работать (то есть закрыть диалог) при первом входе в диалог.

Если диалоговое окно открывается и вы сразу нажимаете ESC , оно не закрывает диалоговое окно (если оно включено), потому что фокус находится на каком-то скрытом поле или чем-то еще, и оно не получает события нажатия клавиши.

Я исправил это, добавив это к событию open, чтобы вместо этого убрать фокус с первого поля:

$('#myDialog').dialog({
    open: function(event,ui) {
        $(this).parent().focus();
    }
});

Это устанавливает фокус на диалоговое окно, которое не отображается, а затем ESCключ работает.


3
Это кажется единственным работающим решением, которое не включает добавление бесполезного HTML, удаление tabindex или взлом ключа ESC.
Боян Бедрач

10

Установите tabindex для ввода в -1, а затем установите dialog.open для восстановления tabindex, если он понадобится вам позже:

$(function() {
    $( "#dialog-message" ).dialog({
        modal: true,
        width: 500,
        autoOpen: false,
        resizable: false,
        open: function()
        {
            $( "#datepicker1" ).attr("tabindex","1");
            $( "#datepicker2" ).attr("tabindex","2");
        }
    });
});

4
Разве tabindex = -1 не помешает мне перейти к текстовому полю?
Slolife

1
Вы могли бы использовать setTimeout, чтобы вернуть tabindex после того, как диалоговое окно показано
redsquare

10

Мой обходной путь:

open: function(){
  jQuery('input:first').blur();
  jQuery('#ui-datepicker-div').hide();
},  

+1. Работает как шарм, используя :firstселектор или .first()в FF / Chrome / IE9. Бросать его в dialogopenпереплет тоже работает.
Nickb

Это тоже привело меня туда. Кроме меня, в моем диалоге вообще не было входных данных, и первая ссылка была в фокусе ... поэтому я добавил эту опцию в свой диалог jQuery:open: function(){ $('a').blur(); // no autofocus on links }
Marcus

8

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

$("#myDialog").dialog({
   ...
   open: function(event, ui) { $(this).scrollTop(0); }
});

Это сработало для меня, но я использовал $('...').blur();вместо прокрутки.
Джава

4
Мое содержание тоже было очень длинным. Размытие убрало выделение, но оставило диалоговое окно прокручиваться вниз. scrollTop прокрутил содержимое до вершины, но оставил выделение. В итоге я использовал $ ('...'). Blur (); $ (это) .scrollTop (0); работал как чемпион.

7

Простой обходной путь:

Просто создайте невидимый элемент с tabindex = 1 ... Это не будет фокусировать средство выбора даты ...

например.:

<a href="" tabindex="1"></a>
...
Here comes the input element

Отлично работает в ie9 и firefox, но не в safari / chrome.
tuseau

3

Вот решение, которое я реализовал после прочтения билета jQuery UI # 4731 , первоначально отправленного slolife как ответ на другой ответ. (Билет был также создан им.)

Во-первых, в любой метод, который вы используете для применения автозаполнения к странице, добавьте следующую строку кода:

$.ui.dialog.prototype._focusTabbable = function(){};

Это отключает поведение автофокуса в jQuery. Чтобы обеспечить доступность вашего сайта, оберните методы создания диалогов, чтобы можно было добавить дополнительный код, и добавьте вызов для фокусировки на первом элементе ввода:

function openDialog(context) {

    // Open your dialog here

    // Usability for screen readers.  Focus on an element so that screen readers report it.
    $("input:first", $(context)).focus();

}

Чтобы дополнительно рассмотреть доступность, когда параметры автозаполнения выбираются с клавиатуры, мы переопределяем обратный вызов автозаполнения в пользовательском интерфейсе jQuery и добавляем дополнительный код, чтобы гарантировать, что textElement не потеряет фокус в IE 8 после выбора.

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

$.fn.applyAutocomplete = function () {

    // Prevents jQuery dialog from auto-focusing on the first tabbable element.
    // Make sure to wrap your dialog opens and focus on the first input element
    // for screen readers.
    $.ui.dialog.prototype._focusTabbable = function () { };

    $(".autocomplete", this)
        .each(function (index) {

            var textElement = this;

            var onSelect = $(this).autocomplete("option", "select");
            $(this).autocomplete("option", {
                select: function (event, ui) {
                    // Call the original functionality first
                    onSelect(event, ui);

                    // We replace a lot of content via AJAX in our project.
                    // This ensures proper copying of values if the original element which jQuery UI pointed to
                    // is replaced.
                    var $hiddenValueElement = $("#" + $(textElement).attr('data-jqui-acomp-hiddenvalue'));
                    if ($hiddenValueElement.attr("value") != ui.item.value) {
                        $hiddenValueElement.attr("value", ui.item.value);
                    }

                    // Replace text element value with that indicated by "display" if any
                    if (ui.item.display)
                        textElement.value = ui.item.display;

                    // For usability purposes.  When using the keyboard to select from an autocomplete, this returns focus to the textElement.
                    $(textElement).focus();

                    if (ui.item.display)
                        return false;

                }
            });
        })
        // Set/clear data flag that can be checked, if necessary, to determine whether list is currently dropped down
        .on("autocompleteopen", function (event, ui) {
            $(event.target).data().autocompleteIsDroppedDown = true;
        })
        .on("autocompleteclose", function (event, ui) {
            $(event.target).data().autocompleteIsDroppedDown = false;
        });

    return this;
}

2

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

.dialog({
      open: function () {
              $(".ui-dialog-titlebar-close").focus();
            }
   });

1

Это может быть поведение браузера, а не проблема с плагином jQuery. Вы пытались удалить фокус программно после открытия всплывающего окна.

$('#lnkAddReservation').click(function () {
    dlg.dialog('open');

    // you may want to change the selector below
    $('input,textarea,select').blur();

    return false;
});

Не проверял это, но должно работать хорошо.


1
к сожалению, это не работает. не уверен, что это IE или JQuery UI. но даже если вы перемещаете фокус на что-то еще программно, календарь остается открытым.
Патриция

1

Я бы решил ту же проблему и решил ее, вставив пустой ввод перед указателем даты, который крадет фокус при каждом открытии диалога. Этот вход скрыт при каждом открытии диалога и снова отображается при закрытии.


1

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

используйте опцию [autoOpen: false]

$toolTip.dialog("widget").css("visibility", "hidden"); 
$toolTip.dialog("open");
$toolTip.dialog("widget").css("visibility", "visible");

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

Я понимаю, что первоначальный пост был просто для того, чтобы не фокусироваться на первом элементе, но вы можете легко решить, где должен быть фокус после открытия диалога (после моего кода).

Проверено в IE, FF и Chrome.

Надеюсь, это кому-нибудь поможет.



1

У меня аналогичная проблема. Я открываю диалоговое окно с ошибкой, когда проверка не проходит, и она захватывает фокус, как это показывает Флуган в своем ответе . Проблема в том, что даже если ни один элемент внутри диалога не является вкладкой, само диалоговое окно все еще находится в фокусе. Вот оригинальный унифицированный код из jquery-ui-1.8.23 \ js \ jquery.ui.dialog.js:

// set focus to the first tabbable element in the content area or the first button
// if there are no tabbable elements, set focus on the dialog itself
$(self.element.find(':tabbable').get().concat(
  uiDialog.find('.ui-dialog-buttonpane :tabbable').get().concat(
    uiDialog.get()))).eq(0).focus();

Комментарий их!

Это действительно плохо для меня по нескольким причинам. Самое неприятное, что первая реакция пользователя состоит в том, чтобы нажать клавишу «Backspace», чтобы удалить последний символ, но вместо этого ему предлагается покинуть страницу, потому что «Backspace» попадает за пределы элемента управления вводом.

Я обнаружил, что следующий обходной путь работает очень хорошо для меня:

jqueryFocus = $.fn.focus;
$.fn.focus = function (delay, fn) {
  jqueryFocus.apply(this.filter(':not(.ui-dialog)'), arguments);
};

Это может быть расширено, чтобы влиять только на определенные диалоги, используя опцию 'dialogClass' в .dialog () и затем изменяя вышеупомянутое: не фильтровать, чтобы включить ваш класс. Например: нет (.ui-dialog.myDialogClass)
Эндрю Мартинес

1

Я искал другую проблему, но ту же причину. Проблема в том, что диалог устанавливает фокус на первое, <a href="">.</a>что находит. Поэтому, если в вашем диалоговом окне много текста и появляются полосы прокрутки, может возникнуть ситуация, когда полоса прокрутки будет прокручена вниз. Я считаю, что это также решает вопрос от первого лица. Хотя другие делают так же.

Простое, легко понять, исправить. <a id="someid" href="#">.</a> как первая строка в вашем диалоге div.

ПРИМЕР:

 <div id="dialogdiv" title="some title">
    <a id="someid" href="#">.</a>
    <p>
        //the rest of your stuff
    </p>
</div>

Где ваш диалог начинается

$(somediv).dialog({
        modal: true,
        open: function () { $("#someid").hide(); otherstuff or function },
        close: function () { $("#someid").show(); otherstuff or function }
    });

Выше не будет ничего сфокусировано, и полосы прокрутки останутся наверху, где он принадлежит. <a>Получает фокус , но затем скрыт. Так что общий эффект - это желаемый эффект.

Я знаю, что это старая ветка, но что касается документации по пользовательскому интерфейсу, это не исправить. Это не требует размытия или фокусировки для работы. Не уверен, что это самый элегантный. Но это просто имеет смысл и легко объяснить кому угодно.


1

Если у вас есть только одно поле в форме диалога Jquery, и именно оно требует Datepicker, в качестве альтернативы, вы можете просто установить фокус на диалоговом окне Закрыть (крестик) в строке заголовка диалога:

$('.ui-dialog-titlebar-close').focus();

Вызов этого ПОСЛЕ диалога был инициализирован, например:

$('#yourDialogId').dialog();
$('.ui-dialog-titlebar-close').focus();

Потому что кнопка закрытия отображается после вызова .dialog().


1

Если вы используете диалоговые кнопки, просто установите autofocusатрибут на одну из кнопок:

$('#dialog').dialog({
  buttons: [
    {
      text: 'OK',
      autofocus: 'autofocus'
    },
    {
      text: 'Cancel'
    }
  ]
});
<script src="https://code.jquery.com/jquery-1.12.4.min.js"></script>
<script src="https://code.jquery.com/ui/1.11.4/jquery-ui.min.js"></script>
<link href="https://code.jquery.com/ui/1.11.4/themes/smoothness/jquery-ui.css" rel="stylesheet"/>

<div id="dialog" title="Basic dialog">
  This is some text.
  <br/>
  <a href="www.google.com">This is a link.</a>
  <br/>
  <input value="This is a textbox.">
</div>


0

У меня та же проблема.

Обходной путь, который я сделал, - добавление пустого текстового поля в верхней части диалогового контейнера.

<input type="text" style="width: 1px; height: 1px; border: 0px;" />

0

Как уже упоминалось, это известная ошибка в jQuery UI, которая должна быть исправлена ​​относительно скоро. До тех пор...

Вот еще один вариант, так что вам не нужно связываться с tabindex:

Временно отключите средство выбора даты, пока не откроется диалоговое окно:

dialog.find(".datepicker").datepicker("disable");
dialog.dialog({
    "open": function() {$(this).find(".datepicker").datepicker("enable");},
});

Работает для меня.

Повторяющийся вопрос: как размыть первый ввод формы при открытии диалога


0

Чтобы раскрыть некоторые из предыдущих ответов (и игнорировать аспект вспомогательного средства выбора даты), если вы хотите, чтобы focus()событие не фокусировалось на первом поле ввода при открытии диалогового окна, попробуйте следующее:

$('#myDialog').dialog(
    { 'open': function() { $('input:first-child', $(this)).blur(); }
});

0

У меня была похожая проблема, и я решил ее, сосредоточившись на диалоге после открытия:

var $dialog = $("#pnlFiltros")
    .dialog({
        autoOpen: false,
        hide: "puff",                   
        width: dWidth,
        height: 'auto',
        draggable: true,
        resizable: true,
        closeOnScape : true,
        position: [x,y]                    
    });
$dialog.dialog('open');
$("#pnlFiltros").focus(); //focus on the div being dialogued (is that a word?)

Но в моем случае первый элемент - это якорь, поэтому я не знаю, если в вашем случае это оставит открытым указатель даты.

РЕДАКТИРОВАТЬ: работает только на IE


0

найти в jquery.ui.js

d.find(".ui-dialog-buttonpane :tabbable").get().concat(d.get()))).eq(0).focus(); 

и заменить на

d.find(".ui-dialog-buttonpane :tabbable").get().concat(d.get()))).eq(-1).focus();

0

Выпущена jQuery 1.9, и, похоже, исправления нет. Попытка предотвратить фокусировку первого текстового поля некоторыми из предложенных методов не работает в 1.9. Я думаю, потому что методы пытаются размыть фокус или переместить фокус, ПОСЛЕ того, как текстовое поле в диалоге уже получило фокус и сделало свою грязную работу.

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


Исправление теперь перенесено в 1.10 в соответствии с заявкой
slolife

0

У меня была похожая проблема. На моей странице первым вводом является текстовое поле с календарем пользовательского интерфейса jQuery. Второй элемент - кнопка. Поскольку дата уже имеет значение, я установил фокус на кнопку, но сначала добавляю триггер для размытия в текстовом поле. Это решает проблему во всех браузерах и, вероятно, во всех версиях jQuery. Протестировано в версии 1.8.2.

<div style="padding-bottom: 30px; height: 40px; width: 100%;">
@using (Html.BeginForm("Statistics", "Admin", FormMethod.Post, new { id = "FormStatistics" }))
{
    <label style="float: left;">@Translation.StatisticsChooseDate</label>
    @Html.TextBoxFor(m => m.SelectDate, new { @class = "js-date-time",  @tabindex=1 })
    <input class="button gray-button button-large button-left-margin text-bold" style="position:relative; top:-5px;" type="submit" id="ButtonStatisticsSearchTrips" value="@Translation.StatisticsSearchTrips"  tabindex="2"/>
}

<script type="text/javascript">
$(document).ready(function () {        
    $("#SelectDate").blur(function () {
        $("#SelectDate").datepicker("hide");
    });
    $("#ButtonStatisticsSearchTrips").focus();

});   


0

Это действительно важно для смартфонов и планшетов, потому что клавиатура появляется, когда фокус ввода фокусируется. Это то, что я сделал, добавьте этот ввод в начале div:

<input type="image" width="1px" height="1px"/>

Не работает с размером 0px. Я думаю, что это даже лучше с настоящим прозрачным изображением, .pngили .gifя не пробовал.

Работает нормально до сих пор в iPad.


-1

Вы можете добавить это:

...

dlg.dialog({ autoOpen:false,
modal: true, 
width: 400,
open: function(){                  // There is new line
  $("#txtStartDate").focus();
  }
});

...


3
Он спрашивает, как предотвратить фокус, а не добавить фокус.
CBarr

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.