Запобігайте діалогу інтерфейсу jQuery від встановлення фокусу до першого текстового поля


156

У мене встановлено модальне діалогове вікно інтерфейсу jQuery для відображення, коли користувач натискає посилання. У цьому діалоговому тезі Div є два текстових поля (я лише показую код на 1 для стислості), і він змінено на текстове поле jQuery UI DatePicker, яке реагує на фокус.

Проблема полягає в тому, що діалогове вікно інтерфейсу jQuery ("відкрито") якимось чином запускає фокус у першому текстовому полі, яке потім запускає календар вибору дати негайно відкритись.

Тому я шукаю спосіб запобігти автоматичному фокусуванню.

<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 вважає це "виправленим", є божевільною. Виправлення полягає в тому, щоб видалити будь-яку логіку автофокусування. Я попросив вас відкрити діалогове вікно, а не зосереджуватися на введенні. Так дратує.
AJB

2
fwiw, я додав вхід w / type = "прихований" над першим входом і додав до нього атрибут автофокусування. Це не означає, що ви думаєте, що це означає, але це працює для вирішення цієї проблеми.
jinglesthula

77

Додайте прихований проміжок над ним, використовуйте доступний інтерфейс-прихований, щоб зробити його прихованим шляхом абсолютного позиціонування. Я знаю, що у вас є цей клас, оскільки ви використовуєте діалог від jquery-ui, і він знаходиться в jquery-ui.

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

1
Чудова робота навколо. Не потрібен js, не змінює макет, а jquery ui підтримує його на початковому рівні.
парі

Погодьтеся, чудова робота навколо. Також приємно знати про прихований доступний клас! Дякую!!
користувач1055761

4
Це спричиняє проблеми людям, які використовують допоміжні технології (наприклад, зчитувачі екрану)
rink.attendant.6

1
@ rink.attendant.6 які проблеми?
oxfn

дивовижне рішення
Педро Коельо

63

У користувальницькому інтерфейсі jQuery> = 1.10.2 ви можете замінити _focusTabbableметод прототипу функцією плацебо:

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

Скрипка

Це вплине на всі dialogs сторінки, не потребуючи редагування кожного вручну.

Оригінальна функція не робить нічого, крім встановлення фокусу на перший елемент з autofocusатрибутом / tabbableелементом / або поверненням до самого діалогу. Оскільки його використання лише встановлює фокус на елементі, не повинно виникнути проблем із його заміною на noop.


7
На цьому горіли години і години, години і години. Мій клієнт дякує вам.
ламаран

1
Це повинна бути відповідь!
брингасол

2 дні шукали це рішення ... нічого більше не працювало ... Дякую багато!
Легіонер

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

1
@Robert, замість того, щоб замінити його $.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 для відкритого.

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 додати можливість відключення цього автофокусування.
slolife

3
@slolife - Вибачте, що воскресив цю справді стару нитку, але цей квиток говорить, що виправлення ( focusSelectorопція) має бути в jQueryUI 1.8, а ми зараз у 1.8.13, і я не бачу цього в діалоговому вікні jQueryUI . Що з цим сталося?
Том Хеммінг

Не звертай уваги. Я бачив, як "історія змінилася з TBD на 1,8" в історії модифікацій, і не помітила, що вона насправді говорить про версію 1.9.
Том Хеммінг

У мене є аналогічна проблема, тут описано моє вирішення - stackoverflow.com/a/12250193/80002
позначити

15

Просто зрозумів це, граючи.

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

Якщо діалогове вікно відкриється, і ви негайно натисніть ESC, воно не закриє діалог (якщо він увімкнено), оскільки фокус знаходиться на якомусь прихованому полі чи чомусь, і він не отримує події натискання клавіші.

Я вирішив, як додати це до відкритої події, щоб замість цього видалити фокус із першого поля:

$('#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обов'язковість теж працює.
нік

Цей мене теж завів. Окрім мене, у моєму діалоговому вікні взагалі не було входів, і перше посилання надавало фокус ... тому я додав цю опцію до свого діалогу jQuery:open: function(){ $('a').blur(); // no autofocus on links }
Марк

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, але не в сафарі / хромі.
тузо

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 UI "select" та додаємо додатковий код, щоб текстElement не втрачав уваги в 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

У мене схожа проблема. Я відкриваю діалог помилок, коли перевірка провалюється, і вона захоплює фокус, як Flugan показує це у своїй відповіді . Проблема полягає в тому, що навіть якщо жоден елемент у діалоговому вікні не є вкладкою, сам діалог все ще зосереджений. Ось оригінальний незмінений код з 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();

Коментар - їхній!

Це дійсно погано для мене з кількох причин. Найбільш дратує те, що перша реакція користувача полягає в тому, щоб потрапити на задній простір, щоб видалити останній символ, але замість нього (-ла) йому запропонують залишити сторінку, тому що в область простору потрапляє поза контролем введення.

Я виявив, що наступне рішення працює для мене досить добре:

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 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 і її слід виправити порівняно скоро. До того як...

Ось ще один варіант, тому вам не доведеться возитися з 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?)

Але в моєму випадку перший елемент є якорем, тому я не знаю, чи у вашому випадку цей датчик залишиться відкритим.

EDIT: працює лише на 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 згідно з квитком jQuery: bugs.jqueryui.com/ticket/4731
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

Це дійсно важливо для смартфонів та планшетів, оскільки клавіатура з'являється, коли вхід має фокус. Це те, що я зробив, додайте цей вхід на початку діла:

<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.