Делегированное событие фокуса в текстовом поле не срабатывает при переходе к элементу

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

$('#forms-container').delegate('.hasInstructions', 'focus', clearInstructions)

hasInstructions - это класс моих элементов ввода с текстом-заполнителем.

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

<textarea class="hasInstructions" onfocus="clearInstructions()">foo</textarea>

Итак, мой вопрос: не всплывают ли события фокуса в текстовых областях? Если да, то как лучше всего это сделать?

РЕДАКТИРОВАТЬ: я знаю, что это не очень похоже на ТАК способ изменить вопрос после его задания. Ответ MikeD полностью соответствует исходному вопросу, и я приму его, если не получу лучшего. Так вот в чем дело,

Я использую jQuery 1.4.2 и не могу использовать более позднюю версию, потому что не загружаю библиотеку на страницу. Я не могу использовать заполнитель HTML5 по причинам совместимости с браузером.


person toofast1227    schedule 19.10.2012    source источник
comment
Является ли #forms-container статическим элементом? Разве вы не можете использовать атрибут заполнителя?   -  person undefined    schedule 19.10.2012
comment
@undefined - да, формы-контейнер - это статический элемент. Я не могу использовать атрибут заполнителя, так как он не поддерживается в старых браузерах, и я не могу использовать плагин jquery, который их имитирует.   -  person toofast1227    schedule 19.10.2012
comment
@toofast Я обновил свой ответ. Посмотрите, работает ли это для вас.   -  person MikeD    schedule 19.10.2012


Ответы (1)


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

Без jQuery

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

Со следующим HTML...

<p id='parent'>
    Enter some values:<br/>
    <input type='text' id='requiredValue'/>
    <input type='text'/>
</p>
<div id='output'>
</div>

... этот JavaScript показывает, что события перехватываются в правильных местах.

var outputDiv = document.getElementById('output'),
    parentDiv = document.getElementById('parent'),
    inputDiv = document.getElementById('requiredValue');

parentDiv.addEventListener('focus', function() {
    outputDiv.innerHTML = outputDiv.innerHTML + "<p>parent</p>";
}, true);
inputDiv.addEventListener('focus', function() {
    outputDiv.innerHTML = outputDiv.innerHTML + "<p>input</p>";
}, true);

Как заставить это работать с IE

Захват событий не работает в IE, однако в упомянутом выше блоге мы видим, что IE поддерживает события focusin и focusout, которые делают то, что вы хотите.

Это означает, что с добавлением еще двух обработчиков событий вы можете обрабатывать этот сценарий во всех случаях:

parentDiv.onfocusin = function() {
    outputDiv.innerHTML = outputDiv.innerHTML + "<p>parent</p>";
};
inputDiv.onfocusout = function() {
    outputDiv.innerHTML = outputDiv.innerHTML + "<p>input</p>";
};

Использование последней версии jQuery

Эта функция работает должным образом при использовании функции 'on.

.on(события [, селектор] [, данные], обработчик (eventObject))

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

Когда предоставляется селектор, обработчик события называется делегированным. Обработчик не вызывается, когда событие происходит непосредственно на привязанном элементе, а только для потомков (внутренних элементов), соответствующих селектору. jQuery перемещает событие от цели события к элементу, к которому прикреплен обработчик (т. е. от самого внутреннего к самому внешнему элементу), и запускает обработчик для любых элементов на этом пути, соответствующих селектору.

Для следующего HTML

<p id='parent'>
    Enter some values:<br/>
    <input type='text' class='requiredValue'/>
    <input type='text'/>
</p>

приведенный ниже код JavaScript работает так, как ожидалось

$(document).ready(function() {
    var initialText = "Enter a value";
    $('.requiredValue').val(initialText);

    $('#parent').on('focus', '.requiredValue', function() {
        var contents = $(this).val();
        if (contents === initialText) {
            $(this).val("");
        }
    });

    $('#parent').on('blur', '.requiredValue', function() {
        var contents = $(this).val();
        if (contents.length == 0) {
            $(this).val(initialText);
        }
    });
});

Техника HTML 5

Лучший метод, совместимый с HTML 5, можно найти здесь. Из блога:

<input type="text" name="first_name" placeholder="Your first name...">

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

Поскольку заполнитель — это новая возможность, важно проверить поддержку в браузере пользователя:

function hasPlaceholderSupport() {
    var input = document.createElement('input');
    return ('placeholder' in input);
}

Если браузер пользователя не поддерживает функцию заполнителя, вам нужно будет использовать запасной вариант с MooTools, Dojo или набором инструментов JavaScript по вашему выбору:

/* mootools ftw! */
var firstNameBox = $('first_name'),
message = firstNameBox.get('placeholder');
firstNameBox.addEvents({
    focus: function() {
        if(firstNameBox.value == message) { searchBox.value = ''; }
    },
    blur: function() {
        if(firstNameBox.value == '') { searchBox.value = message; }
    }
});
person MikeD    schedule 19.10.2012
comment
Спасибо за ответ, но я не могу использовать последнюю версию jQuery. Я использую 1.4.2, и я не могу использовать несовместимый с браузером способ. - person toofast1227; 19.10.2012
comment
Когда вы подтвердили, что использование функции on в более высокой версии jQuery работает, я посмотрел, как это работает. Но все это не имело никакого смысла (наверное, потому что я занят другими делами). И ваш ответ, и ссылки на блог очень полезны. Большое тебе спасибо. - person toofast1227; 21.10.2012