おっしゃる通り、リスト項目を編集する必要はないので、使う理由はありませんcontenteditable
。
必要なのは、リストの現在アクティブな項目に対応するインデックスと、矢印が押されたときにそのインデックスをインクリメントおよびデクリメントする関数です。必要な機能を実装するコンストラクター関数を次に示します。
var NavigableList = function (ul, selectedClass, activeClass) {
var list = null,
index = 0,
walk = function (step) {
var walked = true;
index += step;
if (index < 0 || index === list.length) {
index -= step;
walked = false;
}
return walked;
},
active = false;
this.active = function (state) {
if (state !== active) {
active = state;
if (active) {
ul.addClass(activeClass);
} else {
ul.removeClass(activeClass);
}
}
};
this.isActive = function () {
return active;
};
this.down = function () {
var previous = index,
changed = false;
if (walk(1)) {
$(list[previous]).removeClass(selectedClass);
$(list[index]).addClass(selectedClass);
changed = true;
}
return changed;
};
this.up = function () {
var previous = index,
changed = false;
if (walk(-1)) {
$(list[previous]).removeClass(selectedClass);
$(list[index]).addClass(selectedClass);
changed = true;
}
return changed;
};
this.currentIndex = function () {
return index;
};
this.currentElementx = function () {
return $(list[index]);
};
ul = $(ul);
list = ul.find('>li');
selectedClass = selectedClass || 'current';
activeClass = activeClass || 'active';
$(ul).click(function (e) {
this.active(true);
NavigableList.activeList = this;
}.bind(this));
$(document).keydown(function(e) {
var event = $.Event('change');
if (this.isActive() && e.keyCode === 40) {
if (this.down()) {
event.selected = $(list[index]);
event.index = index;
ul.trigger(event);
}
} else if (this.isActive() && e.keyCode === 38) {
if (this.up()) {
event.selected = $(list[index]);
event.index = index;
ul.trigger(event);
}
}
}.bind(this));
$(list[index]).addClass(selectedClass);
};
これを使うのはとても簡単です:
var list = new NavigableList($('#list'), 'current', 'active'),
list2 = new NavigableList($('#list2'));
$(document).click(function (e) {
if (NavigableList.activeList) {
switch (NavigableList.activeList) {
case list:
list2.active(false);
break;
case list2:
list.active(false);
break;
}
} else {
list.active(false);
list2.active(false);
}
NavigableList.activeList = null;
});
また、次のchange
方法で使用できるリストにイベントを実装しました。
$('#list').change(function (e) {
console.log('List. Selected: ' + e.index);
});
$('#list2').change(function (e) {
console.log('List 2. Selected: ' + e.index);
});
ブラウザ間の互換性のために、すべての Javascript コードの前にこれが必要になります。
if (!Function.prototype.bind) {
Function.prototype.bind = function (oThis) {
if (typeof this !== "function") {
throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");
}
var aArgs = Array.prototype.slice.call(arguments, 1),
fToBind = this,
fNOP = function () {},
fBound = function () {
return fToBind.apply(this instanceof fNOP && oThis
? this
: oThis,
aArgs.concat(Array.prototype.slice.call(arguments)));
};
fNOP.prototype = this.prototype;
fBound.prototype = new fNOP();
return fBound;
};
}
これが実際のデモです。