Вы можете получить доступ к предыдущему и следующему элементам DOM (если есть) с помощью свойств previousSibling
и nextSibling
, к элементам предыдущего и следующего элемента (если есть) с помощью свойства previousElementSibling
и nextElementSibling
. Если элементы, между которыми вы хотите перемещаться, не являются родственными элементами, это становится сложнее. Библиотека JS была бы большой помощью, упрощая обход.
Вы также можете предварительно обрабатывать формы, используя свойство elements
, создавая набор входов в порядке tabIndex
и отслеживая текущий ввод, обновляя всякий раз, когда пользователь нажимает соответствующую клавишу или когда вход усиливает или теряет фокус.
Подход на основе DOM (непроверенный, возможно , вероятно, глючит):
if (! Array.prototype.append) {
Array.prototype.append = function(arr) {
this.push.apply(this, arr);
}
}
if (! Array.prototype.each) {
Array.prototype.each = function(f) {
for (var i=0; i < this.length; ++i) {
f(this[i], i);
}
}
}
if (! Array.prototype.filter) {
Array.prototype.filter = function(f) {
var other = [];
if (!f) {
f = function (x) {return x;};
}
for (var i=0; i < this.length; ++i) {
if (f(this[i])) {
other.push(this[i]);
}
}
return other;
}
}
// call this on the form element
function keyNavigation(form, nextKey, prevKey, modifier) {
if (nextKey) {
nextKey = nextKey.toLowerCase();
} else {
nextKey = 'n';
}
if (prevKey) {
prevKey = prevKey.toLowerCase();
} else {
prevKey = 'p';
}
switch (modifier) {
case 'ctrlKey':
case 'altKey':
case 'metaKey':
break;
case 'ctrl':
case 'alt':
case 'meta':
modifier += 'Key';
break;
default:
modifier = 'ctrlKey';
break;
}
var inputs=[], assigned = [], unassigned=[], input, j=0;
for (var i=0; i < form.elements.length; ++i) {
input = form.elements[i];
if (input.tabIndex) {
j = input.tabIndex;
while(assigned[j]) {++j}
assigned[j] = input;
} else if (!input.disabled) {
unassigned.push(input);
}
}
inputs = assigned.filter();
inputs.append(unassigned);
inputs.each(function (input, keyedIdx) {
input.keyedIdx = keyedIdx;
});
var currIdx;
form.gotoNextInput = function() {
// if currIdx is undefined, comparison should be false
if (currIdx+1 < inputs.length) {
inputs[++currIdx].focus();
}
}
form.gotoPreviousInput = function() {
// if currIdx is undefined, comparison should be false
if (currIdx && currIdx > 0) {
inputs[++currIdx].focus();
}
}
form.addEventListener('keypress', function (evt) {
if (evt[modifier]) {
switch (String.fromCharCode(evt.keyCode).toLowerCase()) {
case nextKey:
evt.stopPropagation();
evt.preventDefault();
this.gotoNextInput();
return false;
case prevKey:
evt.stopPropagation();
evt.preventDefault();
this.gotoPreviousInput();
return false;
}
}
}, true);
// programmatic setting of focus above should invoke this
// handler. Wasteful, but not problematic.
form.addEventListener('focus', function (evt) {
if (typeof evt.target.keyedIdx == 'number') {
currIdx = evt.target.keyedIdx;
}
}, true);
form.addEventListener('blur', function (evt) {
delete currIdx;
}, true);
}