У меня есть элемент div с несколькими промежутками, каждый из которых содержит одно слово. Пользователь может нажать/щелкнуть слово, чтобы выбрать его, но я также пытаюсь реализовать ввод с клавиатуры.
Я хотел бы выделить каждую букву в любых совпадающих словах по мере ввода пользователем.
Например, предположим, что у нас есть эти пять слов:
банан кот малыш мяч конфеты
Если пользователь вводит «ba», я бы хотел выделить первые две буквы в «banana», «baby» и «ball» (тогда, если он наберет «n», буквы в «baby» не будут выделены). " и "мяч" и выделял только первые три буквы слова "банан")
Все эти слова динамически генерируются из массива списка слов, поэтому я надеюсь, что найдется способ добиться такого выделения без необходимости заключать каждую букву в интервал.
Возможно ли это?
🤔 А знаете ли вы, что...
JavaScript имеет множество встроенных объектов, таких как Array, Date и Math.
Чтобы предотвратить добавление элемента span:
Вы можете использовать стиль CSS линейного градиента, чтобы выделить определенную последовательность букв. Измените приведенный ниже код в соответствии с вашими потребностями, поскольку вам может потребоваться выделить несколько вхождений букв в элементе span.
/* index.css */
/* this may be applied if you use <p> other than <span> to wrap your text
p {
display: inline-block;
}
/* update: to ensure each letter has same width */
span {
font-family: monospace;
}
<input type = "text" id = "searchInput" placeholder = "Type to highlight">
<div id = "wordContainer">
<span>banana</span>
<span>cat</span>
<span>baby</span>
<span>ball</span>
<span>candy</span>
</div>
<script>
function highlightWords() {
const searchInput = document.getElementById("searchInput").value.toLowerCase();
const spans = document.querySelectorAll("#word-container span");
spans.forEach((span) => {
const word = span.textContent.toLowerCase();
const wordLength = word.length;
const inputLength = searchInput.length;
// Find the start and end index of the search input within the word
const startIndex = word.indexOf(searchInput);
const endIndex = startIndex + inputLength;
if (startIndex !== -1 && searchInput.length > 0) {
const startPercentage = (startIndex / wordLength) * 100;
const endPercentage = (endIndex / wordLength) * 100;
// Apply the gradient background
span.style.background = `linear-gradient(
to right,
white 0%,
white ${startPercentage}%,
yellow ${startPercentage}%,
yellow ${endPercentage}%,
white ${endPercentage}%,
white 100%
)`;
} else {
span.style.background = "none"; // Reset background if no match
}
});
}
</script>
Вы можете получить текст и ввод, а затем разделить текст на слова, используя Split() , затем перебрать этот массив и проверить, имеет ли значение BeginsWith() любую строку, которую ввод передает во время входного eventListener. Поместив логику в метод карты, вы можете переформатировать искомую строку и объединить оставшуюся часть слова, используя substring() или splice() . Присоединяйтесь к сопоставленному массиву, а затем присвойте элементам innerHTML вновь отформатированную строку с помощью highlight
класса.
Дополнительные комментарии см. во фрагменте кода.
// define variables for the elements in HTML
const par = document.querySelector('#text');
const input = document.querySelector('#matchText');
// callback passing in the event
const searchtext = e => {
// define the input value toLowerCase
const searchText = e.target.value.toLowerCase();
// get the text content of the element you wish to search through
const textCont = par.textContent;
// split the text into words using a whitespace
const words = textCont.split(' ');
// iterate over the words with map and define word
const highlightedText = words.map(word => {
// check and see if the word startWith the searchText string
if (word.toLowerCase().startsWith(searchText) && searchText !== '') {
// return the formatted string of the word
// with the letters highlighted using substring
return `<span class = "highlight">${word.substring(0, searchText.length)}</span><span>${word.substring(searchText.length, word.length)}</span>`;
}
// return the non-matching words in teh original string
return word;
// create a string with the array values using .join()
}).join(' ');
// set the innerHTML to the new string containing the highlighted string
par.innerHTML = highlightedText;
}
// eventListener using an input event, pass the callback
input.addEventListener('input', searchtext);
.highlight {
background-color: yellow;
}
<p id = "text">
<span>Banana</span>
<span>ball</span>
<span>ballistic</span>
<span>cat</span>
<span>chat</span>
<span>change</span>
<span>chap</span>
<span>character</span>
<span>color</span>
<span>people</span>
<span>peel</span>
<span>peon</span>
</p>
<input type = "text" id = "matchText" name = "matchingText">
Может быть, вам нужно следующее? Он также будет выделять буквы или группы букв в середине слов:
// define variables for the elements in HTML
const words = document.querySelectorAll('#text>span');
const input = document.getElementById('matchText');
input.addEventListener("input",()=>{
const rx=new RegExp(input.value,"ig");
words.forEach(w=>w.innerHTML=w.textContent.replace(rx,`<span class = "highlight">$&</span>`));
});
.highlight {
background-color: yellow;
}
<p id = "text">
<span>Banana</span>
<span>ball</span>
<span>ballistic</span>
<span>cat</span>
<span>chat</span>
<span>change</span>
<span>chap</span>
<span>character</span>
<span>color</span>
<span>people</span>
<span>peel</span>
<span>peon</span>
</p>
<input type = "text" id = "matchText" name = "matchingText">
Обновлять
Внимательно прочитав вопрос, я подготовил приведенный выше фрагмент так, чтобы он находил введенные пользователем фрагменты в любом месте каждого слова. Комментарий ОП теперь ясно дал понять, что это было недоразумение, поэтому вот модифицированное решение, которое будет выделять буквы только в начале каждого слова:
// define variables for the elements in HTML
const words = document.querySelectorAll('#text>span');
const input = document.getElementById('matchText');
input.addEventListener("input",()=>{
const rx=new RegExp("^"+input.value,"ig");
words.forEach(w=>w.innerHTML=w.textContent.replace(rx,`<span class = "highlight">$&</span>`));
});
.highlight {
background-color: yellow;
}
<p id = "text">
<span>Banana</span>
<span>ball</span>
<span>ballistic</span>
<span>cat</span>
<span>chat</span>
<span>change</span>
<span>chap</span>
<span>character</span>
<span>color</span>
<span>people</span>
<span>peel</span>
<span>peon</span>
</p>
<input type = "text" id = "matchText" name = "matchingText">
Изменение касается определения регулярного выражения rx
:
const rx=new RegExp("^"+input.value,"ig");
Теперь он всегда начинается с ^
, поэтому шаблон должен находиться в начале каждого <span>
.