innerHTML не работает с более чем одним eventListener в JavaScript-коде «Type Ahead» - PullRequest
0 голосов
/ 31 января 2019

Я работаю над курсом Wes Box Javascript30 и добавляю свои собственные дополнения в код «Type Ahead».Исходный код принимает один источник данных и, используя eventListener, обновляет предложения поиска, возвращая элементы списка в литералах шаблона и обновляя результаты с помощью innerHTML, когда пользователь вводит данные.Я изменил код для поиска по другому набору данных, но теперь я не могу получить функцию «впереди» для правильного обновления предложений.

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

Этот (ответ с наибольшим количеством голосов) предлагает использовать insertAdjacentHTML ().Проблема с этим в моем коде состоит в том, что результаты, которые сопоставляются с меньшим количеством букв, никогда не отфильтровываются, поэтому в итоге получается длинный список результатов, которые больше не соответствуют входным данным.

Javascript -Добавить HTML к элементу контейнера без innerHTML

Я попытался использовать комбинацию createElement и appendChild, но снова я не могу получить результаты, чтобы отфильтровать совпадения, которые больше не применяются.Я ссылался на этот предыдущий вопрос, но не могу решить проблему из ответа, который был принят здесь.

Аргумент 1 Node.appendChild не является объектом при попытке добавить базовый html

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

https://developer.mozilla.org/en-US/docs/Web/API/Element/innerHTML

«Данные» - это всего лишь пример, но они работаюттак же, как данные, которые я использую.Это просто способ сократить его.(Я не могу объединить данные, как это может показаться ниже - это очень упрощено для экономии места)

<form class="search-form">
    <input type="text" class="search" placeholder="Search">
    <ul class="suggestions"></ul>
</form>

<script>
const arr1 = ['pink','blue','green','purple'];
const arr2 = ['red', 'orange', 'yellow', 'black'];

function displayArr1() {
  const matchArray = findMatches(this.value, arr1)
  const html = matchArray.map(item => {
      const regex = new RegExp(this.value, 'gi');
      const itemName = item.replace(regex, `<span class='hl'>${this.value}</span>`);
return `
  <li>
    <span class='name'>${itemName}</span>
  </li>
  `;
 }).join('');
 suggestions.innerHTML = html;
}

function findMatches(wordToMatch, arr) {
    return arr.filter(item => {
        const regex = new RegExp(wordToMatch, 'gi');
        return item.match(regex);
    });
}

function displayArr2() {
  const matchArray = findMatches(this.value, arr2)
  const html = matchArray.map(item => {
      const regex = new RegExp(this.value, 'gi');
      const itemName = item.replace(regex, `<span class='hl'>${this.value}</span>`);
return `
  <li>
    <span class='name'>${itemName}</span>
  </li>
  `;
 }).join('');
 suggestions.innerHTML = html;
}

const searchInput = document.querySelector('.search');
const suggestions = document.querySelector('.suggestions');

searchInput.addEventListener('keyup', displayArr1);
searchInput.addEventListener('keyup', displayArr2);
</script>

Тот же код в JSFiddle: https://jsfiddle.net/slawk/25bt8edw/

Это прекрасно работает только с однимиз списка EventListener (какой бы ни был внизу).Я знаю, что проблема в том, что при использовании innerHTML вы добавляете / уничтожаете элементы, которые удаляют eventListeners.Мне нужно решение, которое позволяет мне отображать предложения из обоих «источников данных» одновременно по мере ввода пользователем.Спасибо.

1 Ответ

0 голосов
/ 31 января 2019

Я думаю, что если вы хотите объединить оба массива, вы можете использовать concat(), но если вы также хотите удалить дублированное значение, вам нужно создать новую функцию, такую ​​как объясняется здесь .

Для его реализации вы можете использовать:

function arrayUnique(array) {
  var a = array.concat();
  for (var i = 0; i < a.length; ++i) {
    for (var j = i + 1; j < a.length; ++j) {
      if (a[i] === a[j])
        a.splice(j--, 1);
    }
  }

  return a;
}
var array3 = arrayUnique(arr1.concat(arr2));

См., Например, jsFiddle Fork или фрагмент кода.

const arr1 = ['pink', 'blue', 'green', 'purple'];
const arr2 = ['red', 'orange', 'yellow', 'black'];

function arrayUnique(array) {
  var a = array.concat();
  for (var i = 0; i < a.length; ++i) {
    for (var j = i + 1; j < a.length; ++j) {
      if (a[i] === a[j])
        a.splice(j--, 1);
    }
  }

  return a;
}
var array3 = arrayUnique(arr1.concat(arr2));

function displayArr() {
  const matchArray = findMatches(this.value, array3)
  const html = matchArray.map(item => {
    const regex = new RegExp(this.value, 'gi');
    const itemName = item.replace(regex, `<span class='hl'>${this.value}</span>`);
    return `
      <li>
        <span class='name'>${itemName}</span>
      </li>
      `;
  }).join('');
  suggestions.innerHTML = html;
}

function findMatches(wordToMatch, arr) {
  return arr.filter(item => {
    const regex = new RegExp(wordToMatch, 'gi');
    return item.match(regex);
  });
}

const searchInput = document.querySelector('.search');
const suggestions = document.querySelector('.suggestions');

searchInput.addEventListener('keyup', displayArr);
<form class="search-form">
  <input type="text" class="search" placeholder="Search">
  <ul class="suggestions"></ul>
</form>
...