Indique a tecla press comporta-se como uma página em Javascript
eu estou olhando para criar um formulário onde pressionando a tecla enter faz com que o foco vá para o elemento "next" do formulário na página. A solução que eu continuo encontrando na web é...
<body onkeydown="if(event.keyCode==13){event.keyCode=9; return event.keyCode}">
Infelizmente, isso só parece funcionar no IE. Então a verdadeira carne desta pergunta é se alguém sabe de uma solução que funciona para FF e cromado? Além disso, eu prefiro não ter que adicionaronkeydown eventos para os próprios elementos de forma, mas se essa é a única maneira, ele terá que fazer.
Esta questão é semelhante à pergunta 905222, mas merecedora da sua própria pergunta, na minha opinião.
Edit: também, eu vi as pessoas abordarem a questão de que este não é um bom estilo, uma vez que diverge do comportamento da forma a que os usuários estão acostumados. Concordo! É um pedido do cliente.
18 answers
$('body').on('keydown', 'input, select, textarea', function(e) {
var self = $(this)
, form = self.parents('form:eq(0)')
, focusable
, next
;
if (e.keyCode == 13) {
focusable = form.find('input,a,select,button,textarea').filter(':visible');
next = focusable.eq(focusable.index(this)+1);
if (next.length) {
next.focus();
} else {
form.submit();
}
return false;
}
});
Map [Enter] key to work like the [Tab] key
Eu reescrevi a resposta de Andre Van Zuydam, que não funcionou comigo, em jQuery. Este caputura tanto entrar como mudar+Enter . indique páginas para a frente, e Shift+indique as páginas de volta.Também reescrevi a forma como self
é inicializado pelo item actual em foco. O formulário também é selecionado dessa forma. Aqui está o código:
// Map [Enter] key to work like the [Tab] key
// Daniel P. Clark 2014
// Catch the keydown for the entire document
$(document).keydown(function(e) {
// Set self as the current item in focus
var self = $(':focus'),
// Set the form by the current item in focus
form = self.parents('form:eq(0)'),
focusable;
// Array of Indexable/Tab-able items
focusable = form.find('input,a,select,button,textarea,div[contenteditable=true]').filter(':visible');
function enterKey(){
if (e.which === 13 && !self.is('textarea,div[contenteditable=true]')) { // [Enter] key
// If not a regular hyperlink/button/textarea
if ($.inArray(self, focusable) && (!self.is('a,button'))){
// Then prevent the default [Enter] key behaviour from submitting the form
e.preventDefault();
} // Otherwise follow the link/button as by design, or put new line in textarea
// Focus on the next item (either previous or next depending on shift)
focusable.eq(focusable.index(self) + (e.shiftKey ? -1 : 1)).focus();
return false;
}
}
// We need to capture the [Shift] key and check the [Enter] key either way.
if (e.shiftKey) { enterKey() } else { enterKey() }
});
A razão textarea
Está incluído porque nós" queremos " abarcar nele. Além disso, uma vez dentro, não queremos parar o comportamento padrão de Enter de colocar em uma nova linha.
A razão a
e button
Permitir a acção por omissão, " e" ainda se concentra no próximo item, porque eles nem sempre carregam outra página. Pode haver um gatilho / efeito sobre aqueles como um acordeão ou conteúdo abaulado. Então, uma vez ... despoleta o comportamento padrão, e a página faz seu efeito especial, você ainda quer ir para o próximo item, uma vez que seu gatilho pode ter introduzido bem.
$(document).on('keydown', ':tabbable', function (e) {
if (e.which == 13 || e.keyCode == 13 )
{ e.preventDefault();
var $canfocus = $(':tabbable:visible')
var index = $canfocus.index(document.activeElement) + 1;
if (index >= $canfocus.length) index = 0;
$canfocus.eq(index).focus();
}
});
Acabei de adicionar o evento de mudança na função acima para voltar entre os elementos, pensei que alguém pudesse precisar disto.
$('body').on('keydown', 'input, select, textarea', function(e) {
var self = $(this)
, form = self.parents('form:eq(0)')
, focusable
, next
, prev
;
if (e.shiftKey) {
if (e.keyCode == 13) {
focusable = form.find('input,a,select,button,textarea').filter(':visible');
prev = focusable.eq(focusable.index(this)-1);
if (prev.length) {
prev.focus();
} else {
form.submit();
}
}
}
else
if (e.keyCode == 13) {
focusable = form.find('input,a,select,button,textarea').filter(':visible');
next = focusable.eq(focusable.index(this)+1);
if (next.length) {
next.focus();
} else {
form.submit();
}
return false;
}
});
Há problemas com todas as implementações dadas aqui. Alguns não funcionam corretamente com áreas de texto e enviar botões, a maioria não permite que você use shift para ir para trás, nenhum deles usa tabindexes se você os tem, e nenhum deles se envolve do último para o primeiro ou o primeiro para o último.
Para que a tecla [enter] actue como a tecla [tab], mas ainda funcione correctamente com as áreas de texto e os botões enviar usem o seguinte código. Além disso, este código permite-lhe usar o shift key to go backward and the tabbing wraps around front to back and back to front.
Código-Fonte: https://github.com/mikbe/SaneEnterKey
CoffeeScript
mbsd_sane_enter_key = ->
input_types = "input, select, button, textarea"
$("body").on "keydown", input_types, (e) ->
enter_key = 13
tab_key = 9
if e.keyCode in [tab_key, enter_key]
self = $(this)
# some controls should just press enter when pressing enter
if e.keyCode == enter_key and (self.prop('type') in ["submit", "textarea"])
return true
form = self.parents('form:eq(0)')
# Sort by tab indexes if they exist
tab_index = parseInt(self.attr('tabindex'))
if tab_index
input_array = form.find("[tabindex]").filter(':visible').sort((a,b) ->
parseInt($(a).attr('tabindex')) - parseInt($(b).attr('tabindex'))
)
else
input_array = form.find(input_types).filter(':visible')
# reverse the direction if using shift
move_direction = if e.shiftKey then -1 else 1
new_index = input_array.index(this) + move_direction
# wrap around the controls
if new_index == input_array.length
new_index = 0
else if new_index == -1
new_index = input_array.length - 1
move_to = input_array.eq(new_index)
move_to.focus()
move_to.select()
false
$(window).on 'ready page:load', ->
mbsd_sane_enter_key()
JavaScript
var mbsd_sane_enter_key = function() {
var input_types;
input_types = "input, select, button, textarea";
return $("body").on("keydown", input_types, function(e) {
var enter_key, form, input_array, move_direction, move_to, new_index, self, tab_index, tab_key;
enter_key = 13;
tab_key = 9;
if (e.keyCode === tab_key || e.keyCode === enter_key) {
self = $(this);
// some controls should react as designed when pressing enter
if (e.keyCode === enter_key && (self.prop('type') === "submit" || self.prop('type') === "textarea")) {
return true;
}
form = self.parents('form:eq(0)');
// Sort by tab indexes if they exist
tab_index = parseInt(self.attr('tabindex'));
if (tab_index) {
input_array = form.find("[tabindex]").filter(':visible').sort(function(a, b) {
return parseInt($(a).attr('tabindex')) - parseInt($(b).attr('tabindex'));
});
} else {
input_array = form.find(input_types).filter(':visible');
}
// reverse the direction if using shift
move_direction = e.shiftKey ? -1 : 1;
new_index = input_array.index(this) + move_direction;
// wrap around the controls
if (new_index === input_array.length) {
new_index = 0;
} else if (new_index === -1) {
new_index = input_array.length - 1;
}
move_to = input_array.eq(new_index);
move_to.focus();
move_to.select();
return false;
}
});
};
$(window).on('ready page:load', function() {
mbsd_sane_enter_key();
}
O fragmento mais simples de baunilha JS que encontrei:
document.addEventListener('keydown', function (event) {
if (event.keyCode === 13 && event.target.nodeName === 'INPUT') {
var form = event.target.form;
var index = Array.prototype.indexOf.call(form, event.target);
form.elements[index + 1].focus();
event.preventDefault();
}
});
Trabalha em navegadores IE 9+ e modernos.
Mudar este comportamento cria realmente uma experiência de utilizador muito melhor do que o comportamento predefinido implementado nativamente. Considere que o comportamento da tecla enter já é inconsistente do ponto de vista de usuário, pois em uma única linha de entrada, digite tende a apresentar um formulário, enquanto em uma multi-linha textarea, ele simplesmente adiciona uma nova linha para o conteúdo do campo.
Recentemente fiz assim (usa jQuery):$('input.enterastab, select.enterastab, textarea.enterastab').live('keydown', function(e) {
if (e.keyCode==13) {
var focusable = $('input,a,select,button,textarea').filter(':visible');
focusable.eq(focusable.index(this)+1).focus();
return false;
}
});
Isto não é muito eficiente, mas funciona. bem o suficiente e é confiável - basta adicionar a classe 'enterastab' a qualquer elemento de entrada que deve se comportar desta forma.
angular.module('myapp', [])
.directive('pdkNextInputOnEnter', function() {
var includeTags = ['INPUT', 'SELECT'];
function link(scope, element, attrs) {
element.on('keydown', function (e) {
// Go to next form element on enter and only for included tags
if (e.keyCode == 13 && includeTags.indexOf(e.target.tagName) != -1) {
// Find all form elements that can receive focus
var focusable = element[0].querySelectorAll('input,select,button,textarea');
// Get the index of the currently focused element
var currentIndex = Array.prototype.indexOf.call(focusable, e.target)
// Find the next items in the list
var nextIndex = currentIndex == focusable.length - 1 ? 0 : currentIndex + 1;
// Focus the next element
if(nextIndex >= 0 && nextIndex < focusable.length)
focusable[nextIndex].focus();
return false;
}
});
}
return {
restrict: 'A',
link: link
};
});
Eis como o uso no aplicativo em que estou trabalhando, apenas adicionando a diretiva pdk-next-input-on-enter
sobre um elemento. Estou usando um scanner de código de barras para inserir dados em campos, a função padrão do scanner é para eMule um keayboard, injectando uma tecla enter após digitar os dados do código de barras digitalizado.
Existe um efeito secundário neste código (positivo para o meu caso de uso), se ele se concentrar num botão, o evento enter keyup fará com que a acção do botão seja activada. Isto funcionou muito bem para o meu fluxo como o último elemento de forma na minha marcação é um botão que eu quero ativado uma vez que todos os campos foram "tabbed" através de varredura de códigos de barras.
<!DOCTYPE html>
<html ng-app=myapp>
<head>
<script src="angular.min.js"></script>
<script src="controller.js"></script>
</head>
<body ng-controller="LabelPrintingController">
<div class='.container' pdk-next-input-on-enter>
<select ng-options="p for p in partNumbers" ng-model="selectedPart" ng-change="selectedPartChanged()"></select>
<h2>{{labelDocument.SerialNumber}}</h2>
<div ng-show="labelDocument.ComponentSerials">
<b>Component Serials</b>
<ul>
<li ng-repeat="serial in labelDocument.ComponentSerials">
{{serial.name}}<br/>
<input type="text" ng-model="serial.value" />
</li>
</ul>
</div>
<button ng-click="printLabel()">Print</button>
</div>
</body>
</html>
PlusAsTab : um 'plugin' jQuery para usar a tecla numpad plus como equivalente a uma tecla tab.
Já que queres entra/↵ em vez disso, você pode definir as opções. Descubra qual a chave que deseja usar com o evento jQuery .qual demo .
JoelPurra.PlusAsTab.setOptions({
// Use enter instead of plus
// Number 13 found through demo at
// https://api.jquery.com/event.which/
key: 13
});
// Matches all inputs with name "a[]" (needs some character escaping)
$('input[name=a\\[\\]]').plusAsTab();
Podes experimentar. você mesmo no PlusAsTab digite como Tab demo .
function ModifyEnterKeyPressAsTab(event)
{
var caller;
var key;
if (window.event)
{
caller = window.event.srcElement; //Get the event caller in IE.
key = window.event.keyCode; //Get the keycode in IE.
}
else
{
caller = event.target; //Get the event caller in Firefox.
key = event.which; //Get the keycode in Firefox.
}
if (key == 13) //Enter key was pressed.
{
cTab = caller.tabIndex; //caller tabIndex.
maxTab = 0; //highest tabIndex (start at 0 to change)
minTab = cTab; //lowest tabIndex (this may change, but start at caller)
allById = document.getElementsByTagName("input"); //Get input elements.
allByIndex = []; //Storage for elements by index.
c = 0; //index of the caller in allByIndex (start at 0 to change)
i = 0; //generic indexer for allByIndex;
for (id in allById) //Loop through all the input elements by id.
{
allByIndex[i] = allById[id]; //Set allByIndex.
tab = allByIndex[i].tabIndex;
if (caller == allByIndex[i])
c = i; //Get the index of the caller.
if (tab > maxTab)
maxTab = tab; //Get the highest tabIndex on the page.
if (tab < minTab && tab >= 0)
minTab = tab; //Get the lowest positive tabIndex on the page.
i++;
}
//Loop through tab indexes from caller to highest.
for (tab = cTab; tab <= maxTab; tab++)
{
//Look for this tabIndex from the caller to the end of page.
for (i = c + 1; i < allByIndex.length; i++)
{
if (allByIndex[i].tabIndex == tab)
{
allByIndex[i].focus(); //Move to that element and stop.
return;
}
}
//Look for the next tabIndex from the start of page to the caller.
for (i = 0; i < c; i++)
{
if (allByIndex[i].tabIndex == tab + 1)
{
allByIndex[i].focus(); //Move to that element and stop.
return;
}
}
//Continue searching from the caller for the next tabIndex.
}
//The caller was the last element with the highest tabIndex,
//so find the first element with the lowest tabIndex.
for (i = 0; i < allByIndex.length; i++)
{
if (allByIndex[i].tabIndex == minTab)
{
allByIndex[i].focus(); //Move to that element and stop.
return;
}
}
}
}
Para usar este código, adicione - o à sua marca de entrada em html:
<input id="SomeID" onkeydown="ModifyEnterKeyPressAsTab(event);" ... >
Ou adicioná - lo a um elemento em javascript:
document.getElementById("SomeID").onKeyDown = ModifyEnterKeyPressAsTab;
Um par de outros notas:
Eu só precisava dele para trabalhar nos meus elementos de entrada, mas você poderia estendê-lo a outros elementos de Documento se você precisar. Para isso, getElementsByClassName é muito útil, mas esse é um tópico completamente diferente.
Uma limitação é que ele só abarca entre os elementos que você adicionou ao seu conjunto allById. Não abarca as outras coisas que o seu navegador poderá ter, como barras de ferramentas e menus fora do seu documento html. Talvez esta seja uma característica em vez de uma limitacao. Se você quiser, trap keyCode 9 e este comportamento irá funcionar com a tecla tab também.
Pode usar o meu código abaixo, testado em Mozilla, IE e Chrome
// Use to act like tab using enter key
$.fn.enterkeytab=function(){
$(this).on('keydown', 'input, select,', function(e) {
var self = $(this)
, form = self.parents('form:eq(0)')
, focusable
, next
;
if (e.keyCode == 13) {
focusable = form.find('input,a,select,button').filter(':visible');
next = focusable.eq(focusable.index(this)+1);
if (next.length) {
next.focus();
} else {
alert("wd");
//form.submit();
}
return false;
}
});
}
Como utilizar?
$("#forma").enterkeytab (); / / enter key tab
Se puder, eu reconsideraria fazer isto: a acção por omissão de premir {[[0]} enquanto num formulário submete o formulário e tudo o que fizer para alterar esta acção por omissão / comportamento esperado poderá causar alguns problemas de usabilidade com o site.
Vanilla js com suporte para Shift + Enter e capacidade de escolher quais tags HTML são focáveis. Deve funcionar mais de 9.
onKeyUp(e) {
switch (e.keyCode) {
case 13: //Enter
var focusableElements = document.querySelectorAll('input, button')
var index = Array.prototype.indexOf.call(focusableElements, document.activeElement)
if(e.shiftKey)
focus(focusableElements, index - 1)
else
focus(focusableElements, index + 1)
e.preventDefault()
break;
}
function focus(elements, index) {
if(elements[index])
elements[index].focus()
}
}
$(document).ready(function () {
$.fn.enterkeytab = function () {
$(this).on('keydown', 'input,select,text,button', function (e) {
var self = $(this)
, form = self.parents('form:eq(0)')
, focusable
, next
;
if (e.keyCode == 13) {
focusable = form.find('input,a,select').filter(':visible');
next = focusable.eq(focusable.index(this) + 1);
if (next.length) {
//if disable try get next 10 fields
if (next.is(":disabled")){
for(i=2;i<10;i++){
next = focusable.eq(focusable.index(this) + i);
if (!next.is(":disabled"))
break;
}
}
next.focus();
}
return false;
}
});
}
$("form").enterkeytab();
});
<script type="text/javascript" language="javascript">
function convertEnterToTab() {
if(event.keyCode==13) {
event.keyCode = 9;
}
}
document.onkeydown = convertEnterToTab;
</script>
Em todos esses casos, só funciona no Chrome e IE, adicionei o seguinte código para resolver isso:
Var key = (janela.evento)? E. keyCode: E. which;
E eu testei o valor da chave em if keycode é igual a 13
$('body').on('keydown', 'input, select, textarea', function (e) {
var self = $(this)
, form = self.parents('form:eq(0)')
, focusable
, next
;
var key = (window.event) ? e.keyCode : e.which;
if (key == 13) {
focusable = form.find('input,a,select,button,textarea').filter(':visible');
next = focusable.eq(focusable.index(this) + 1);
if (next.length) {
next.focus();
} else {
focusable.click();
}
return false;
}
});
Você poderia programaticamente iterar os elementos de forma adicionando o controlador onkeydown enquanto você vai. Desta forma você pode reutilizar o código.