Как в данном примере отменить действия браузера по умолчанию при использовании стрелок вверх/вниз?
let input = document.querySelector('.input'),
variants = document.querySelector('.variantsDiv'),
wordsObject = {
'a' : ['amy', 'any', 'aky', 'ammy', 'aby', 'aty', 'azy', 'ally', 'aly'],
'b' : ['boy', 'boom', 'by', 'burn', 'build', 'back', 'background', 'boo'],
'p' : ['pick', 'pook']
};
let varMod = (function(){
/////////////////////////// (1) ///////////////////////////
function createSpanItems(input, variantsBlock, objOfWords){
let val = input.value.toLowerCase(),
firstLetter = val.slice(0,1).toLowerCase(),
curArray,
variants = [];
if(objOfWords[firstLetter]){
curArray = objOfWords[firstLetter];
}else{
return;
};
for(let k=0; k<curArray.length; k++){
if(curArray[k].indexOf(val)!==-1){
variants.push(curArray[k]);
};
};
if(!variants.length){
variantsBlock.style.opacity = 0;
return;
}
varMod.clearVars(variantsBlock);
for(let k=0; k<variants.length; k++){
let itemSpan = document.createElement('span');
itemSpan.textContent = variants[k];
itemSpan.setAttribute('value', variants[k]);
itemSpan.classList.add('varianItem');
variantsBlock.appendChild(itemSpan);
itemSpan.innerHTML = itemSpan.textContent.replace(
val,
(m)=>{
return `<span style="color: orange">${m}</span>`;
}
);
};
};
/////////////////////////// (1) ///////////////////////////
/////////////////////////// (2) ///////////////////////////
function clearVariants(variantsBlock){
while(variantsBlock.firstChild){
variantsBlock.removeChild(variantsBlock.firstChild)
};
};
/////////////////////////// (2) ///////////////////////////
return {
createSpan : createSpanItems,
clearVars : clearVariants
};
})();
document.addEventListener('click', (e)=>{
if(e.target.className === 'varianItem'){
varMod.clearVars(variants);
variants.style.opacity = 0;
input.value = e.target.getAttribute('value');
}
});
input.addEventListener('input', function(e){
let val = input.value.toLowerCase(),
firstLetter = val.slice(0,1).toLowerCase();
if(!val){
varMod.clearVars(variants);
variants.style.opacity = 0;
}
if(!wordsObject[firstLetter]) return;
if(val){
variants.style.opacity = 1;
varMod.createSpan(input, variants, wordsObject);
};
});
*{
box-sizing: border-box;
margin: 0;
padding: 0;
}
body{
background: aliceblue;
}
.input-wrapper{
display: block;
position: relative;
margin: 240px auto;
width: 300px;
height: 36px;
}
.input, .variantsDiv{
width: 100%;
background-color: ghostwhite;
border-radius: 5px;
letter-spacing: 1.5px;
font-family: 'Arial';
font-size: 19px;
}
.input{
display: block;
padding: 0px 12px 0px 12px;
position: relative;
height: 100%;
font-family: 'Arial'
}
.variantsDiv{
min-height: 36px;
position: absolute;
top: 125%;
left: 0px;
border: 2px solid gray;
opacity: 0;
transition: all 0.3s;
max-height: 300px;
overflow-Y: scroll;
}
.varianItem{
display: block;
width: 100%;
height: 36px;
line-height: 36px;
padding: 0px 12px 0px 12px;
}
.varianItem:hover{
cursor: pointer;
background: #e0e0e0;
}
<div class="input-wrapper">
<input type="text" class="input">
<div class="variantsDiv">
</div>
</div>
Делаю инпут с автозаполнением, мне нужно чтобы в инпуте работали стрелки вниз/вверх ( как вы уже догадались для выбора вариантов ), но не знаю как отменить стандартное действие браузера по умолчанию ! Подскажите пожалуйста, чот я даже отследить событие нажатия этих пнопок вверх / вниз не могу ! p.s.: пока в объекте на автозаполнение прописал только слова на три буквы " a , b , p ", чисто для тестов!
Ответы (1 шт):
Что добавил:
В CSS: Рядом с :hover, .varianItem.active — элементы с обоими классами получат те же стили.
input.addEventListener("keydown", function(e) {
if (!/Arrow(Up|Down)/.test(e.key)) return; // Если не стрелки - прервать;
e.preventDefault(); // Дошло сюда, значит стрелки. Блокировать поведение по умолчанию;
let suggestions = document.querySelectorAll(".variantsDiv .varianItem");
if (suggestions.length == 0) return; // Подходящих слова нет - прервать;
let active = document.querySelector(".variantsDiv .varianItem.active");
let curr_index = [].indexOf.call(suggestions, active);
// Номер текущего активного слова среди всех предложенных
let change_index = e.key.includes("Up") ? -1 : 1;
// Стрелка вверх ? надо будет уменьшить индекс на 1 : вниз - увеличть.
let new_index = (curr_index + change_index + suggestions.length) % suggestions.length;
if (active) active.classList.remove("active");
suggestions[new_index].classList.add("active");
});
Здесь curr_index может получить значение -1, если класс active еще никуда не добавлен (null). В таком случае если тыкнули стрелку вверх, нужно превращать его в = suggestions.length чтобы выделился нижний элемент. Чтобы не уродовать код здесь, в цикле for( k... variants) добавил строчку if (k == 0) itemSpan.classList.add('active'); — по умолчанию всегда первый элемент будет выделен.
let input = document.querySelector('.input'),
variants = document.querySelector('.variantsDiv'),
wordsObject = {
'a': ['amy', 'any', 'aky', 'ammy', 'aby', 'aty', 'azy', 'ally', 'aly'],
'b': ['boy', 'boom', 'by', 'burn', 'build', 'back', 'background', 'boo'],
'p': ['pick', 'pook']
};
let varMod = (function() {
/////////////////////////// (1) ///////////////////////////
function createSpanItems(input, variantsBlock, objOfWords) {
let val = input.value.toLowerCase(),
firstLetter = val.slice(0, 1).toLowerCase(),
curArray,
variants = [];
if (objOfWords[firstLetter]) {
curArray = objOfWords[firstLetter];
} else {
return;
};
for (let k = 0; k < curArray.length; k++) {
if (curArray[k].indexOf(val) !== -1) {
variants.push(curArray[k]);
};
};
if (!variants.length) {
variantsBlock.style.opacity = 0;
return;
}
varMod.clearVars(variantsBlock);
for (let k = 0; k < variants.length; k++) {
let itemSpan = document.createElement('span');
itemSpan.textContent = variants[k];
itemSpan.setAttribute('value', variants[k]);
itemSpan.classList.add('varianItem');
if (k == 0) itemSpan.classList.add('active');
variantsBlock.appendChild(itemSpan);
itemSpan.innerHTML = itemSpan.textContent.replace(
val,
(m) => {
return `<span style="color: orange">${m}</span>`;
}
);
};
};
/////////////////////////// (1) ///////////////////////////
/////////////////////////// (2) ///////////////////////////
function clearVariants(variantsBlock) {
while (variantsBlock.firstChild) {
variantsBlock.removeChild(variantsBlock.firstChild)
};
};
/////////////////////////// (2) ///////////////////////////
return {
createSpan: createSpanItems,
clearVars: clearVariants
};
})();
document.addEventListener('click', (e) => {
if (e.target.className === 'varianItem') {
varMod.clearVars(variants);
variants.style.opacity = 0;
input.value = e.target.getAttribute('value');
}
});
input.addEventListener("keydown", function(e) {
if (!/Arrow(Up|Down)/.test(e.key)) return;
e.preventDefault();
let suggestions = document.querySelectorAll(".variantsDiv .varianItem");
if (suggestions.length == 0) return;
let active = document.querySelector(".variantsDiv .varianItem.active");
let curr_index = [].indexOf.call(suggestions, active);
let change_index = e.key.includes("Up") ? -1 : 1;
let new_index = (curr_index + change_index + suggestions.length) % suggestions.length;
if (active) active.classList.remove("active");
suggestions[new_index].classList.add("active");
});
input.addEventListener('input', function(e) {
let val = input.value.toLowerCase(),
firstLetter = val.slice(0, 1).toLowerCase();
if (!val) {
varMod.clearVars(variants);
variants.style.opacity = 0;
}
if (!wordsObject[firstLetter]) return;
if (val) {
variants.style.opacity = 1;
varMod.createSpan(input, variants, wordsObject);
};
});
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
background: aliceblue;
}
.input-wrapper {
display: block;
position: relative;
margin: 40px auto;
width: 300px;
height: 36px;
}
.input,
.variantsDiv {
width: 100%;
background-color: ghostwhite;
border-radius: 5px;
letter-spacing: 1.5px;
font-family: 'Arial';
font-size: 19px;
}
.input {
display: block;
padding: 0px 12px 0px 12px;
position: relative;
height: 100%;
font-family: 'Arial'
}
.variantsDiv {
min-height: 36px;
position: absolute;
top: 125%;
left: 0px;
border: 2px solid gray;
opacity: 0;
transition: all 0.3s;
max-height: 300px;
overflow-Y: scroll;
}
.varianItem {
display: block;
width: 100%;
height: 36px;
line-height: 36px;
padding: 0px 12px 0px 12px;
}
.varianItem.active, .varianItem:hover {
cursor: pointer;
background: #e0e0e0;
}
<div class="input-wrapper">
<input type="text" class="input">
<div class="variantsDiv">
</div>
</div>
Там еще придется возиться со скроллом. Быстрое решение: suggestions[new_index].scrollIntoView();
https://developer.mozilla.org/ru/docs/Web/API/Element/scrollIntoView - нужно поизучать параметры, или более детально всё прописать, через scrollTop / getBoundingClientRect()