web-dev-qa-db-ger.com

Eingabetaste verhält sich wie ein Tab in Javascript

Ich möchte ein Formular erstellen, bei dem durch Drücken der Eingabetaste der Fokus zum nächsten Formularelement auf der Seite wechselt. Die Lösung, die ich im Internet immer wieder finde, ist ...

 <body onkeydown="if(event.keyCode==13){event.keyCode=9; return event.keyCode}">

Leider scheint das nur im IE zu funktionieren. Das eigentliche Fleisch dieser Frage ist, wenn jemand eine Lösung kennt, die für FF und Chrome funktioniert? Außerdem muss ich nicht lieber onkeydown -Ereignisse zu den Formularelementen selbst hinzufügen, aber wenn dies der einzige Weg ist, muss dies auch der Fall sein.

Dieses Problem ähnelt der Frage 905222 , verdient aber meiner Meinung nach eine eigene Frage.

Edit: Ich habe auch gesehen, dass die Leute das Problem ansprechen, dass dies kein guter Stil ist, da es vom gewohnten Formularverhalten abweicht. Genau! Es ist eine Kundenanfrage :(

62
Ross

Ich habe die von Andrew vorgeschlagene Logik verwendet, die sehr effektiv ist. Und das ist meine Version:

$('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;
    }
});
78
tcdona

Ordnen Sie die [Enter] -Taste so zu, dass sie wie die [Tab] -Taste funktioniert

Ich habe die Antwort von Andre Van Zuydam , die bei mir nicht funktioniert hat, in jQuery umgeschrieben. Dies erfasst beides Enter und Shift+EnterEnter Tabs vorwärts und Shift+Enter Tabs zurück.

Ich habe auch die Art und Weise umgeschrieben, wie self durch das aktuelle Objekt im Fokus initialisiert wird. Auf diese Weise wird auch das Formular ausgewählt. Hier ist der Code:

// 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() }
});

Der Grund textarea

ist enthalten, weil wir " tun " wollen, um in es zu tappen. Außerdem möchten wir das Standardverhalten von nicht mehr stoppen Enter vom Einfügen einer neuen Zeile.

Der Grund a und button

erlauben die Standardaktion, " und " konzentrieren sich immer noch auf das nächste Element, weil sie nicht immer eine andere Seite laden. Es kann einen Trigger/Effekt auf solche wie Akkordeon- oder Tabbed-Inhalte geben. Sobald Sie also das Standardverhalten auslösen und die Seite ihren Spezialeffekt ausführt, möchten Sie immer noch zum nächsten Element wechseln, da Ihr Auslöser es möglicherweise gut eingeführt hat.

18
6ft Dan

Das hat für mich funktioniert

 $(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();
}   

});

JsFiddle

13
Mayur Sarang

Danke für das gute Drehbuch.

Ich habe gerade das Schichtereignis für die obige Funktion hinzugefügt, um zwischen den Elementen zurückzukehren.

$('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;
}
});
11

Bei allen hier aufgeführten Implementierungen gibt es Probleme. Einige funktionieren nicht ordnungsgemäß mit Textfeldern und Übergabeschaltflächen, die meisten erlauben nicht die Verwendung von Shift, um rückwärts zu gehen. Keiner von ihnen verwendet Tabindexes, wenn Sie solche haben, und keiner von ihnen springt vom letzten zum ersten oder ersten bis zum letzten.

Damit die [Eingabetaste] wie die [Tabulatortaste] fungiert, aber dennoch ordnungsgemäß mit Textbereichen und Senden-Schaltflächen funktioniert, verwenden Sie den folgenden Code. Außerdem können Sie mit diesem Code die Umschalttaste verwenden, um rückwärts zu gehen, und das Tabbing wird von vorne nach hinten und von vorne nach hinten umbrochen.

Quellcode: 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();
}
6
Mike Bethany

Der einfachste Vanilla JS-Ausschnitt, den ich mir ausgedacht habe:

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();
  }
});

Funktioniert in IE 9+ und modernen Browsern.

5

Das Ändern dieses Verhaltens führt tatsächlich zu einer weitaus besseren Benutzererfahrung als das nativ implementierte Standardverhalten. Beachten Sie, dass das Verhalten der Eingabetaste aus Sicht des Benutzers bereits inkonsistent ist, da Enter bei einer einzeiligen Eingabe dazu neigt, ein Formular zu übermitteln, während es in einem mehrzeiligen Textbereich einfach eine neue Zeile zum Inhalt der Feld.

Ich habe es kürzlich so gemacht (verwendet 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;
 }
});

Dies ist nicht besonders effizient, funktioniert jedoch gut genug und ist zuverlässig. Fügen Sie einfach die Enterastab-Klasse zu jedem Eingabeelement hinzu, das sich so verhalten soll.

4
Andrew

Ich überarbeitete die OPs-Lösung in eine Knockout-Bindung und dachte, ich würde sie teilen. Vielen Dank :-)

Hier ist a Fiddle 

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head>
    <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js" type="text/javascript"></script>
    <script src="http://ajax.aspnetcdn.com/ajax/knockout/knockout-2.2.1.js" type="text/javascript"></script>


</head>
<body>

    <div data-bind="nextFieldOnEnter:true">
        <input type="text" />
        <input type="text" />
        <select>
          <option value="volvo">Volvo</option>
          <option value="saab">Saab</option>
          <option value="mercedes">Mercedes</option>
          <option value="audi">Audi</option>
        </select>
        <input type="text" />
        <input type="text" />
    </div>


    <script type="text/javascript">
    ko.bindingHandlers.nextFieldOnEnter = {
        init: function(element, valueAccessor, allBindingsAccessor) {
            $(element).on('keydown', 'input, select', function (e) {
                var self = $(this)
                , form = $(element)
                  , focusable
                  , next
                ;
                if (e.keyCode == 13) {
                    focusable = form.find('input,a,select,button,textarea').filter(':visible');
                    var nextIndex = focusable.index(this) == focusable.length -1 ? 0 : focusable.index(this) + 1;
                    next = focusable.eq(nextIndex);
                    next.focus();
                    return false;
                }
            });
        }
    };

    ko.applyBindings({});
    </script>
</body>
</html>
4
Damien Sawyer

Hier ist eine eckige.js-Anweisung, mit der Sie zum nächsten Feld gehen und die anderen Antworten als Inspiration verwenden können. Es gibt hier vielleicht etwas seltsam aussehenden Code, da ich nur die mit eckig gepackte jQlite verwende. Ich glaube, dass die meisten Funktionen hier in allen Browsern> IE8 funktionieren.

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
    };
});

So verwende ich es in der App, an der ich gerade arbeite, indem ich einfach die pdk-next-input-on-enter-Direktive zu einem Element hinzufüge. Ich verwende einen Barcode-Scanner, um Daten in Felder einzugeben. Die Standardfunktion des Scanners besteht darin, ein Keayboard zu emulieren, wobei nach Eingabe der Daten des gescannten Barcodes eine Eingabetaste eingegeben wird.

Dieser Code hat einen Nebeneffekt (einen positiven für meinen Anwendungsfall). Wenn der Fokus auf eine Schaltfläche verschoben wird, bewirkt das Ereignis enter keyup, dass die Aktion der Schaltfläche aktiviert wird. Dies funktionierte sehr gut für meinen Ablauf, da das letzte Formularelement in meinem Markup eine Schaltfläche ist, die aktiviert werden soll, wenn alle Felder durch Scannen von Barcodes durchgesteuert wurden.

<!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>
2
joshperry

Ich hatte ein ähnliches Problem, bei dem ich drücken wollte + auf dem Nummernblock, um zum nächsten Feld zu wechseln. Jetzt habe ich eine Bibliothek veröffentlicht, von der ich denke, dass sie Ihnen helfen wird.

PlusAsTab : Ein jQuery-Plugin zur Verwendung der Zifferntasten-Plus-Taste als Tabulator-Äquivalent.

Da willst du enter/ Stattdessen können Sie die Optionen festlegen. Finden Sie heraus, welchen Schlüssel Sie mit der jQuery event.which-Demo verwenden möchten.

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();

Sie können es selbst in der PlusAsTab als Registerkarte Demo eingeben ausprobieren.

1
Joel Purra

Wenn Sie können, würde ich dies noch einmal überdenken: Die Standardaktion, indem Sie auf <Enter> drücken, während Sie in einem Formular das Formular absenden, und alles, was Sie zur Änderung dieser Standardaktion/des erwarteten Verhaltens tun, kann zu Usability-Problemen mit der Site führen.

0
Ian Oxley

Vanilla Js mit Unterstützung für Shift + Enter und der Möglichkeit zu wählen, welche HTML-Tags fokussierbar sind. Sollte IE9 + funktionieren.

  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()
    }
  }
0
jiv-e

Folgendes habe ich mir ausgedacht.

form.addEventListener("submit", (e) => { //On Submit
 let key = e.charCode || e.keyCode || 0 //get the key code
 if (key = 13) { //If enter key
    e.preventDefault()
    const inputs = Array.from(document.querySelectorAll("form input")) //Get array of inputs
    let nextInput = inputs[inputs.indexOf(document.activeElement) + 1] //get index of input after the current input
    nextInput.focus() //focus new input
}
}
0

Versuche dies...

$(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();
});
0
Lucio Pelinson

Ich habe es nur in JavaScript. Firefox lässt Sie den keyCode nicht aktualisieren. Sie können also nur keyCode 13 abfangen und ihn durch tabIndex auf das nächste Element konzentrieren, als ob keyCode 9 gedrückt wurde. Der schwierige Teil ist das Finden des nächsten TabIndex. Ich habe dies nur auf IE8-IE10 und Firefox getestet und es funktioniert:

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;
            }
        }
    }
}

Um diesen Code zu verwenden, fügen Sie ihn Ihrem HTML-Eingabe-Tag hinzu:

<input id="SomeID" onkeydown="ModifyEnterKeyPressAsTab(event);" ... >

Oder fügen Sie es einem Element in Javascript hinzu:

document.getElementById("SomeID").onKeyDown = ModifyEnterKeyPressAsTab;

Ein paar andere Notizen:

Ich brauchte es nur, um meine Eingabeelemente zu bearbeiten, aber Sie könnten es bei Bedarf auf andere Dokumentelemente erweitern. Dafür ist getElementsByClassName sehr hilfreich, aber das ist ein ganz anderes Thema.

Eine Einschränkung besteht darin, dass nur Registerkarten zwischen den Elementen angezeigt werden, die Sie zu Ihrem allById-Array hinzugefügt haben. Es werden keine anderen Elemente angezeigt, die Ihr Browser möglicherweise bietet, z. B. Symbolleisten und Menüs außerhalb Ihres HTML-Dokuments. Vielleicht ist dies eine Funktion anstelle einer Einschränkung. Wenn Sie möchten, fangen Sie keyCode 9 ab. Dieses Verhalten funktioniert auch mit der Tabulatortaste.

0
Jroonk

Viele Antworten hier verwenden e.keyCode und e.which, die veraltet sind.

Verwenden Sie stattdessen e.key === 'Enter'.

Dokumentation: https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/keyCode

  • Es tut mir leid, aber ich kann diese Schnipsel gerade nicht testen. Komme später wieder, nachdem ich es getestet habe.

Mit HTML:

<body onkeypress="if(event.key==='Enter' && event.target.form){focusNextElement(event); return false;}">

Mit jQuery:

$(window).on('keypress', function (ev)
{
    if (ev.key === "Enter" && ev.currentTarget.form) focusNextElement(ev)
}

Mit Vanille JS:

document.addEventListener ('keypress', function (ev) {if (ev.key === "Enter" && ev.currentTarget.form) focusNextElement (ev);});

Sie können die Funktion focusNextElement() von hier aus übernehmen: https://stackoverflow.com/a/35173443/3356679

0
oriadam

Sie können meinen Code verwenden, der in Mozilla, IE und Chrome getestet wurde

   // 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;
            }
        });

    }

Wie benutzt man?

$ ("# form"). enterkeytab (); // Schlüssel eingeben

0
Francis Tudlong