Enterキーをトラップしますが、ブラウザーのオートコンプリート候補を選択するときはトラップしません
-
22-07-2019 - |
質問
ページにいくつかのテキストボックスがあり、ユーザーがそれらのいずれかでEnterキーを押したときにリンクをクリックしたい。
JavaScriptを使用してEnterボタンを簡単にトラップできます( event.keyCode
および event.which
で13を探します)が、ブラウザーのオートコンプリート時に問題が発生します機能が起動し、ユーザーが入力したいものを提案します。ユーザーがTabキーではなく、Enterキーを押してブラウザーの提案を受け入れることがよくあります。これは、リンクがすぐにクリックされるため、ユーザーを混乱させますが、他のフィールドの一部にテキストを入力することを意図しています。
ここでフォームと送信ボタンを使用する方が良いと思いますが、さまざまな理由で実用的ではありません。
jQueryを使用しているので、jQueryソリューションを提供してください。
解決
ユーザーは、オートコンプリートテキストのいずれかを選択する場合は常に下キーを押す必要があり、下キーを押したときに変数を何かに設定して、その後Enterキーを押すと、変数。変数が設定されている場合はリンククリック機能を実行しないでください。そうでない場合は通常どおり実行してください。
他のヒント
受け入れられた回答でtuanvtのアイデアを使用して、仕事をするjQueryプラグインを作成しました。
ユーザーが上、下、ページ上、およびページ下のキーを押して、オートコンプリートボックスにいることを確認したときを追跡します。他のすべてのキーは、彼らがそれを残したことを意味します。
これらのルールをテキストボックスにのみ適用することを確認します。他のすべての入力要素は正常に動作します。
Operaは、私が達成しようとしていたことについてすでにかなり良い仕事をしているので、そのブラウザでルールを強制しません。そうしないと、ユーザーはEnterを2回押す必要があります。
IE6、IE7、IE8、Firefox 3.5.5、Google Chrome 3.0、Safari 4.0.4、Opera 10.00でテスト済み。
jquery.comで SafeEnterプラグインとして入手できます。便宜上、リリース1.0のコードは次のとおりです。
// jQuery plugin: SafeEnter 1.0
// http://plugins.jquery.com/project/SafeEnter
// by teedyay
//
// Fires an event when the user presses Enter, but not whilst they're in the browser's autocomplete suggestions
//codesnippet:2e23681e-c3a9-46ce-be93-48cc3aba2c73
(function($)
{
$.fn.listenForEnter = function()
{
return this.each(function()
{
$(this).focus(function()
{
$(this).data('safeEnter_InAutocomplete', false);
});
$(this).keypress(function(e)
{
var key = (e.keyCode ? e.keyCode : e.which);
switch (key)
{
case 13:
// Fire the event if:
// - we're not currently in the browser's Autocomplete, or
// - this isn't a textbox, or
// - this is Opera (which provides its own protection)
if (!$(this).data('safeEnter_InAutocomplete') || !$(this).is('input[type=text]') || $.browser.opera)
{
$(this).trigger('pressedEnter', e);
}
$(this).data('safeEnter_InAutocomplete', false);
break;
case 40:
case 38:
case 34:
case 33:
// down=40,up=38,pgdn=34,pgup=33
$(this).data('safeEnter_InAutocomplete', true);
break;
default:
$(this).data('safeEnter_InAutocomplete', false);
break;
}
});
});
};
$.fn.clickOnEnter = function(target)
{
return this.each(function()
{
$(this)
.listenForEnter()
.bind('pressedEnter', function()
{
$(target).click();
});
});
};
})(jQuery);
すべてのブラウザの標準ではありませんが、一般的なブラウザで動作しますが、チェックボックスでオートコンプリートをオフにしてみてください。
<input type="text" autocomplete="off" />
JQueryは優れているが、単純なJavaScriptを使用しないのはなぜですか?
function submit_on_enter(e) {
var keycode;
if (window.event) keycode = window.event.keyCode;
else if (e) keycode = (e.keyCode ? e.keyCode : e.which);
else return true;
if (keycode == 13) {
if (window.previousKeyCode) {
// down=40,up=38,pgdn=34,pgup=33
if (window.previousKeyCode == 33 || window.previousKeyCode == 34 ||
window.previousKeyCode == 39 || window.previousKeyCode == 40) {
window.previousKeyCode = keycode;
return true;
}
}
submit_form();
return false;
} else {
window.previousKeyCode = keycode;
return true;
}
}
キーアップイベントでEnterキーを追跡し、キーアップイベントでEnterキーを検出するまでに選択が完了します。
キーダウンでエンターキーを検出し、操作がオートコンプリート機能を妨害します。
これは私のために働く:
$('input').keypress(function(e) {
if(e.which == 13) {
if(this.value)
{
$("#submitbutton").click();
}
}
});
新しいhtml5フォームフィールドタイプを使用している場合、teedyayのコードを次のように変更できます。
case 13:
// Fire the event if:
// - we're not currently in the browser's Autocomplete, or
// - this isn't a textbox, or
// - this is Opera (which provides its own protection)
if (!$(this).data('safeEnter_InAutocomplete') || !$(this).is('input([type=text],[type=email],[type=number],[type=search],[type=tel],[type=url])') || $.browser.opera)
{
...
新しい入力タイプに注意してください。
ウィンドウまたは特定のDOM要素でキーの押下をトラップしているかどうかはわかりません。後者(たとえば、 form
要素)を実行し、イベントハンドラーでイベントオブジェクトを調べて、どのDOM要素がイベントの発生元であるかを判断する必要があります。これがオートコンプリート付きのテキストフィールドである場合、 return false;
。
jQueryの .keypress()
イベントハンドラ、および event.target
イベントオブジェクトのプロパティ。
同じ問題に直面しましたが、完璧ではありませんが、よりシンプルだと思う別のアプローチを使用しました。オートコンプリートを作成するときに、選択イベントの現在の時間を設定し、アクションを実行する前にそれを比較します。
$('#completer').autocomplete({
source: ['First', 'Last'], delay: 0, minLength: 0,
select: function(ev, ui) {
$(ev.target).data('lastAutocompleteSelectTimestamp', new Date().getTime())
}
})
$(document).on('keydown', '#completer', function(ev){
if (ev.which != 13) return
var lastAutocompletionTime = $(ev.currentTarget).data('lastAutocompleteSelectTimestamp')
if (!lastAutocompletionTime || (new Date().getTime() - lastAutocompletionTime) > 100)
alert('Enter pressed outside autocomplete context')
})
<html>
<head>
<link href="https://code.jquery.com/ui/1.11.0/themes/smoothness/jquery-ui.css" rel="stylesheet"/>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script src="https://code.jquery.com/ui/1.11.0/jquery-ui.min.js"></script>
</head>
<body>
<input id=completer type=text />
</body>
</html>
別の(より安全な)アプローチは、 keyup
および keydown
イベントを使用して値の変更を検出することです。
オートコンプリートは、 keyDown
イベントの後に値を設定します。両方のイベントが観察された場合、以下は他のソリューションよりもはるかに信頼性が高くなります。
var tempValue;
// fire when enter is 1. pressed and 2. released
function handlerEnter(type){
// save the value for comparison
if(type == 'keyDown'){
tempValue = document.activeElement.value;
return null; // quit
}
// quit when the value changed in between keyDown & keyUp
if(type == 'keyUp' && tempValue != document.activeElement.value){
return null;
}
// autocomplete wasn't used
doStuff();
}
document.activeElement が入力であるかどうかを確認できます。 私の邪悪なプロトタイプ拡張を使用してください。