Запобігайте діалогу інтерфейсу 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.