Есть ли способ динамически выделить определенные буквы в слове, не делая каждую букву отдельным элементом <span>?

У меня есть элемент div с несколькими промежутками, каждый из которых содержит одно слово. Пользователь может нажать/щелкнуть слово, чтобы выбрать его, но я также пытаюсь реализовать ввод с клавиатуры.

Я хотел бы выделить каждую букву в любых совпадающих словах по мере ввода пользователем.

Например, предположим, что у нас есть эти пять слов:

банан кот малыш мяч конфеты

Если пользователь вводит «ba», я бы хотел выделить первые две буквы в «banana», «baby» и «ball» (тогда, если он наберет «n», буквы в «baby» не будут выделены). " и "мяч" и выделял только первые три буквы слова "банан")

Все эти слова динамически генерируются из массива списка слов, поэтому я надеюсь, что найдется способ добиться такого выделения без необходимости заключать каждую букву в интервал.

Возможно ли это?

выделенный ban поверх обычного banana

jsotola 25.08.2024 05:05

Этот вопрос похож на: JavaScript найти строку и выделить. Если вы считаете, что это другое, отредактируйте вопрос, поясните, чем он отличается и/или как ответы на этот вопрос не помогают решить вашу проблему.

PM 77-1 25.08.2024 05:12

Вам не обязательно обертывать каждую букву заранее, но да, вам придется обернуть каждую последовательность букв, которую вы хотите выделить.

Bergi 25.08.2024 05:42
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
0
3
80
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Чтобы предотвратить добавление элемента 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>

Это решение предполагает, что все буквы имеют одинаковую ширину.

Heiko Theißen 25.08.2024 09:13

О, @HeikoTheißen, спасибо, что указали на это. Возможно, мы можем добавить «font-family: monospace» к элементу span.

Steven Low 25.08.2024 09:53

Вы можете получить текст и ввод, а затем разделить текст на слова, используя 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>.

Если вы решите использовать такое решение, было бы целесообразно включить aria-метку в элементы диапазона, например «<span aria-label='Banana'>Banana</span>». Таким образом, люди с нарушениями зрения по-прежнему смогут понимать контент, и это никак не повлияет на людей без инвалидности.

TheQueenOfCSS 25.08.2024 12:32

Ах, сказал слишком рано. Я тоже пропустил немного выделения в середине слов. Есть ли способ изменить вызов RegExp(), чтобы он соответствовал только словам, начинающимся со строки?

1337ingDisorder 25.08.2024 19:13

Я изменил свой ответ соответственно. Пожалуйста, проверьте.

Carsten Massmann 26.08.2024 06:19

Ага! Спасибо, я знал, что это такая маленькая обработка! Я даже попробовал изменить «ig» на «^ig» после поиска кое-что о регулярных выражениях, но я не до конца понял это, и, очевидно, это не сработало. Мне в голову не пришло, что я ввел неправильный параметр, ха-ха... Еще раз спасибо!

1337ingDisorder 27.08.2024 03:33

Другие вопросы по теме