Добавляем в компонент свойство - индекс выделенного элемента выпадающего списка:
const searchIndex = ref(-1);
По нажатию на стрелки делаем ему плюс-минус один:
function onKeydown({ key }) {
if (key === 'Escape') {
searchQuery.value = '';
return;
}
const data = filteredProducts.value ?? [];
const { length } = data;
if (length) {
const index = searchIndex.value;
const step = +(key === 'ArrowDown') || -(key === 'ArrowUp');
if (step) {
searchIndex.value = (Math.max(-1, index + step) + length) % length;
} else if (key === 'Enter' && index !== -1) {
onSelectProduct(data[index]);
}
}
}
watch(() => !!searchQuery.value.length, value => value
? document.addEventListener('keydown', onKeydown)
: document.removeEventListener('keydown', onKeydown)
);
В зависимости от равенства значения этого свойства текущему индексу в
v-for
, назначаем элементу списка класс, который его визуально выделит:
.active {
background: #ccc;
}
<li
v-for="(n, i) in filteredProducts"
:key="n.id"
:class="{ active: i === searchIndex }"
@mouseenter="searchIndex = i"
@click="onSelectProduct(n)"
>
Если при изменении данных, на основе которых строится список, надо сбросить выделение, создаём соответствующий наблюдатель:
watch(filteredProducts, () => searchIndex.value = -1);
Вот как-то так.