Вариант раз. Нужно знать два индекса - элемента внешнего массива и элемента внутреннего, добавим в компонент соответствующее свойство:
data: () => ({
active: [ 0, -1 ],
...
При переходе к следующему/предыдущему элементу изменяем внутренний индекс, если вышли за границу внутреннего массива, переходим к следующим/предыдущим элементам внешнего массива, пока не встретится такой, у которого внутри что-то есть; внутренний индекс при этом сбрасываем в крайнее положение - чтобы соответствовал первому или последнему элементу вложенного массива, в зависимости от направления движения:
methods: {
onKeyDown(e) {
const { items } = this;
const step = ({
ArrowUp: -1,
ArrowDown: 1,
})[e.key];
if (step && items.some(n => n.children?.length)) {
let iItem = this.active[0];
let iChild = this.active[1] + step;
while (!items[iItem].children?.[iChild]) {
iItem = (iItem + step + items.length) % items.length;
iChild = step === 1 ? 0 : ~-items[iItem].children?.length;
}
this.active = [ iItem, iChild ];
}
},
...
Осталось выделить как активный тот DOM-элемент, индексы которого совпадают с сохранёнными в экземпляре компонента, назначаем класс при равенстве обоих пар значений:
<ul>
<li v-for="(item, iItem) in items">
<ul>
<li
v-for="(child, iChild) in item.children"
:class="{ active: active[0] === iItem && active[1] === iChild }"
...
Вариант два - развернём в общий плоский массив элементы вложенных массивов:
computed: {
children() {
return this.items.flatMap(n => n.children ?? []);
},
...
Тогда можно будет обойтись одним индексом:
data: () => ({
active: null,
...
Которому просто делаем +/- 1:
methods: {
onKeyDown({ key }) {
const { length } = this.children;
const step =
key === 'ArrowUp' ? -1 :
key === 'ArrowDown' ? 1 :
0;
if (step && length) {
const active = this.active ?? (step === 1 ? -1 : length);
this.active = Math.max(0, Math.min(length - 1, active + step));
}
},
...
Если элемент вложенного массива совпадает с тем, который можно достать из плоского массива, воспользовавшись индексом, добавим соответствующему DOM-элементу класс:
<ul>
<li v-for="item in items">
<ul>
<li
v-for="child in item.children"
:class="{ active: children[active] === child }"
...