Нахождение первого фокусируемого элемента любого типа в пределах div - PullRequest
3 голосов
/ 05 января 2010

У меня есть требование в Javascript (с использованием Prototype), чтобы фокусировать курсор на первом элементе формы в определенном div.

Простой пример:

<form id="theForm">
  <div id="part1">
    <input id="aaa" .../>
    <select id="bbb">...</select>
  </div>
  <div id="part2">
    <select id="ccc">...</select>
    <input id="ddd" .../>
  </div>
</form>

Я хочу написать функцию Javascript, которая принимает имя div внутри theForm и фокусирует курсор на первом элементе в этом div - например,

focusOnFirst('part1'); // will put focus on input "aaa"
focusOnFirst('part2'); // will put focus on select "ccc"

Я думал, что смогу использовать метод выбора Prototype, подобный этому:

$(pDiv).select('input','select',...etc.);

Однако, это возвращает массив, который содержит все входные данные, сопровождаемые всеми выборами, и т. Д. Он не возвращает элементы в порядке, в котором они появляются внутри div. В моем примере выше это приводит к фокусированию на вводе «ddd», а не на «ccc».

Другой возможностью является метод getElements формы:

$('theForm').getElements();

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

Кто-нибудь может предложить лучший способ?

Ответы [ 2 ]

1 голос
/ 05 января 2010

Вот что мне удалось придумать:

focusFirstItem (divId)
{
    if ($(divId))
    {
        var elems = $('myForm').getElements();
        for (i=0, l=elems.length; i<l; ++i) {
            var item = $(elems[i]);
            if (!item.disabled && !item.readOnly && item.visible) {
                if (item.ancestors().find(function(s){return s.id == divId})) {
                    $(item).focus();
                    break;
                }
            }
        }
    }
}

Ужасно, я знаю. На IE6 требуется около полсекунды, намного лучше 70 мс или около того на FF. Я знаю, что смогу избавиться от цикла «for» с помощью Prototype, но я потерпел неудачу в своих попытках сделать это.

1 голос
/ 05 января 2010

Как насчет использования селектора CSS3:

$$('#theForm input:first-of-type')[0].focus()

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

Я подготовил быстрый пример .

- Редактировать ОК, я только что понял, что он пропускает элемент выбора.

- Edit. Это похоже на работу - выберите первый элемент с атрибутом name (при условии, что у вас есть атрибуты name, вы можете использовать что-то еще):

function focusOnFirst2(divName) {
    $$('#' + divName + ' [name]')[0].focus();
}

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

- Изменить В последний раз:)

Я взял вашу функцию и попытался ее перевернуть, чтобы она осуществляла поиск по дочерним элементам div, а не по дочерним элементам формы. Я поместил его в цикл, чтобы вызвать его 100 раз, и вижу улучшение IE на ~ 45%, будет ли это лучше для вас в реальном мире, я не уверен:

function focusFirstItem (divId)
{
    if ($(divId))
    {
        var elems = $('myForm').getElements();
        var elems2 = $(divId).select('*');
        for (i=0, l=elems2.length; i<l; ++i) {
            var item = elems2[i];
            if (item.id && !item.disabled && !item.readOnly && item.visible) {
                if (elems.find(function(s){return s.id = item.id}))
                item.focus();
                break;
            }
        }
    }
}

В примере страницы с элементарным временем .

...