Почему здесь используется обработчик keyup, и могу ли я предотвратить его?
Рассмотрим следующий HTML5 + Javascript:
$(function() {
$('#edit').hide();
$('#value')
.css('cursor', 'pointer')
.click(function() {
$('#edit').show();
$('#edit input').focus();
$('#value').hide();
});
$('#edit input')
.keyup(function(e) {
if (e.keyCode == 13) { // <enter>
$('#value').show();
$('#edit').hide();
}
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="value">
<a href="#">hello</a>
</div>
<div id="edit">
<input type="text" value="hello" />
</div>
Ответы
Ответ 1
Здесь альтернативное решение. Единственная разница в функциональности заключается в том, что вход только появляется и фокусируется при отпускании клавиши ввода. Он прослушивает keydown
и предотвращает щелчок по умолчанию по умолчанию, а затем выполняет обмен в событии keyup
, чтобы keyup
не попадал в поле ввода. Я пробовал его в IE 11, Chrome и Firefox, все в Windows.
$(function() {
$('#edit').hide();
$('#value')
.css('cursor', 'pointer')
.click(function() {
$('#edit').show();
$('#edit input').focus();
$('#value').hide();
});
$('#value a')
.keydown(function(e) { // Prevent default enter click
if (e.keyCode == 13) {
e.preventDefault();
e.stopPropagation();
}
}).keyup(function(e) {
if (e.keyCode == 13) {
e.preventDefault();
e.stopPropagation();
$('#edit').show();
$('#edit input').focus();
$('#value').hide();
}
});
$('#edit input')
.keyup(function(e) {
if (e.keyCode == 13) { // <enter>
$('#value').show();
$('#edit').hide();
}
});
});
Ответ 2
Таким образом, проблема заключается в том, что при нажатии клавиши ввода событие keyup
запускается при отпускании ключа.
Это создает поток, подобный следующему:
1, нажмите ссылку (нажмите клавишу ввода)
2, ссылки скрыты
3, основное внимание уделяется вводу текста (клавиша ввода в данный момент нажата)
4, выпуск ключа (событие keyup уволено)
Если вы измените событие на keydown
, то нажатие на ссылку не приведет к конфликту ввода, потому что этот вход не имеет фокуса.
Кроме того, использование того же кода в событии keydown, которое у вас было в событии keyup, по-прежнему будет делать то же самое (например, нажмите "Enter", а окна ввода скрываются и отображается ссылка).
ИЗМЕНИТЬ
https://jsfiddle.net/geyut7uv/
Единственное твердое решение, которое я смог найти, заключалось в создании "блокирующей" переменной, которая "отключает" событие keydown. Я привязал его к ссылке только при нажатии клавиши. Это проверяется на событии keydown с помощью ввода, который будет немедленно активирован, если пользователь удерживает клавишу нажатой.
Это только тогда, когда срабатывает событие key key key, которое позволяет пропускать переменную "blocker".
В идеале я хотел бы удалить все глобальные переменные области видимости, но я не смог найти способ узнать, что в настоящее время используется событие (keydown).
<div id="value">
<a href="#">hello</a>
</div>
<div id="edit">
<input type="text" value="hello" />
</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script type="text/javascript">
$(function() {
var enter_enabled = true;
$('#edit').hide();
$('#value')
.css('cursor', 'pointer')
.click(function() {
$('#edit').show();
$('#edit input').focus();
$('#value').hide();
}).keydown(function(e){
enter_enabled = false;
});
$('#edit input')
.keydown(function(e){
if(e.keyCode == 13 && enter_enabled){
$('#value').show();
$('#edit').hide();
}
})
.keyup(function(e){
if(e.keyCode == 13){
enter_enabled = true;
}
});
});
</script>
Ответ 3
Я пошел по пути использования флага обновленный скрипт снова:
html остается неизменным, но js немного меняется. Я добавил переменную valueClicked и установил ее в false; Затем используйте это как условие в keyup, однако, после проверки условия keyup, я reset флаг.
$(function() {
var valueClickedFromEnter = false;
$('#edit').hide();
function handleLinkClick(event)
{
$('#edit').show();
$('#edit input').focus();
$('#value').hide();
valueClickedFromEnter =
(event.keyCode && event.keyCode == 13);
}
$('#value')
.css('cursor', 'pointer')
.keydown(handleLinkClick).click(handleLinkClick);
$('#edit input')
.keyup(function(e) {
if (e.keyCode == 13 && !valueClickedFromEnter) { // <enter>
$('#value').show();
$('#edit').hide();
}
valueClickedFromEnter = false;
});
});
Идея заключается в том, что всякий раз, когда вы нажимаете enter от tabbing до привязки, устанавливается флаг, проверяется клавиша, а затем флаг reset, поэтому при следующем входе условие переходит. Затем, используя его обычно, флаг никогда не устанавливается, поэтому условие все равно проходит.
Отредактировано: на основе обратной связи clientX и clientY не являются межсерверными решениями. Вместо этого я использовал промежуточную функцию для обработки событий keydown и click для привязывающего тега, передавая объект события. Затем этот объект проверяется на свойство ключа, если ему 13, тогда флаг переключается.
Дополнительным преимуществом является то, что использование другого ключа, например пробела, также приводит к переключению ссылки, и если пользователь начинает вводить текст, он войдет во вход.
Ответ 4
Обновлен, чтобы исправить проблему с длинным нажатием. Проблема проста: у вас было прослушивание событий в режиме keyup, вы специально выделили этот элемент, поэтому он запускал, когда пользователь выпустил ключ.
Обновление № 2:
Это должно работать в полной мере, по иронии судьбы, мне пришлось изменить свое первоначальное изменение, чтобы выполнить все при скрытии элемента.
Попробуйте следующее:
var enterPressed = false;
var enteredExclusion = false;
$(document).ready(function() {
$('#edit').hide();
$('#value')
.css('cursor', 'pointer')
.click(function() {
$('#value').hide();
$('#edit').show();
$('#editabletext').focusin(function(e){
enteredExclusion = true;
}).focusout(function(e){
enterPressed = false;
enteredExclusion = false;
}).focus();
});
$('#editabletext')
.keydown(function(e){
if (e.keyCode == 13 && !enteredExclusion) { // <enter>
console.log('setting true');
enterPressed = true;
}
})
.keyup(function(e) {
enteredExclusion = false;
if (e.keyCode == 13 && (enterPressed )) {
$('#value').show();
$('#edit').hide();
console.log('setting false - keyup');
enterPressed = false;
}
});
});
HTML:
<div id="value">
<a href="#">hello</a>
</div>
<div id="edit">
<input id="editabletext" type="text" value="hello" />
</div>
Ответ 5
Вместо того, чтобы возиться с флагами и еще много чего, я решил отключить элемент input
, когда он не отображается. Отключенные элементы не могут получать фокус, поэтому теоретически у вас не будет проблемы, при которой клавиша Enter все еще поднимается, пока элемент активен.
Я также явно устанавливаю фокус на привязку, когда клавиша Enter нажата в элементе input
. Это гарантирует, что фокус больше не находится на этом элементе, прежде чем отключать его, что может вызвать проблемы.
Обратите внимание, что я тестировал это только в Chrome 42 (oh и FF 36 и IE 11) в Windows 8.1, поэтому YMMV.
$(function() {
$('#edit').hide();
var keyupHandler = function(e) {
if (e.keyCode === 13) { // <enter>
$('#value').show().focus();
$('#edit').hide().find('input').prop('disabled', true);
}
};
var clickHandler = function(e) {
$('#value').hide();
$('#edit').show(500, function() {
$(this).find('input').prop('disabled', false).focus();
});
e.preventDefault();
};
$('#value').on('click', clickHandler);
$('#edit').on('keydown', 'input', keyupHandler);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="value">
<a href="#">hello</a>
</div>
<div id="edit">
<input type="text" value="hello" />
</div>
Ответ 6
Что происходит, похоже, следующее:
1) Пользователь нажимает вводить на сфокусированный элемент → это вызывает событие клика, а также событие keyup. Сначала запускается событие click.
2) Будет вызван обработчик щелчка по #value
. Этот обработчик показывает поле #edit
и устанавливает фокус на этом поле.
3) Событие keyup запускается. Но поскольку теперь основное внимание уделяется #edit
, оно будет запущено для этого поля (!)
4) Будет вызываться обработчик keyup на #edit
и снова скрывает поле #edit
.