Автозаполнение JavaScript без внешней библиотеки

Есть ли библиотека автозаполнения javascript, которая не зависит от каких-либо других библиотек?

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

Ответ 1

Здесь - базовый пример JavaScript, который можно изменить в элемент управления автозаполнением:

var people = ['Steven', 'Sean', 'Stefan', 'Sam', 'Nathan'];

function matchPeople(input) {
  var reg = new RegExp(input.split('').join('\\w*').replace(/\W/, ""), 'i');
  return people.filter(function(person) {
    if (person.match(reg)) {
      return person;
    }
  });
}

function changeInput(val) {
  var autoCompleteResult = matchPeople(val);
  document.getElementById("result").innerHTML = autoCompleteResult;
}
<input type="text" onkeyup="changeInput(this.value)">
<div id="result"></div>

Ответ 2

Для тех, кто смотрит на это в 2017 году, кому нужно простое решение, вы можете использовать встроенный <datalist> HTML5 вместо того, чтобы полагаться на JavaScript.

Пример:

<datalist id="languages">
  <option value="HTML">
  <option value="CSS">
  <option value="JavaScript">
  <option value="Java">
  <option value="Ruby">
  <option value="PHP">
  <option value="Go">
  <option value="Erlang">
  <option value="Python">
  <option value="C">
  <option value="C#">
  <option value="C++">
</datalist>

<input type="text" list="languages">

Обратите внимание, что это не будет работать в Safari (по состоянию на апрель 2017 года).

https://developer.mozilla.org/en-US/docs/Web/HTML/Element/datalist

Ответ 3

Ядром сценария автозаполнения будет аякс-вызов словаря терминов.

Я предполагаю, что ваше мобильное приложение уже включает функцию ajax, так что, может быть, вам лучше просто написать свой автозаполнение с нуля? В основном все, что вам нужно во входном теге, обработчик события keyup, который запускает вызов ajax, и div для сбора ответа.

[Обновление] Основываясь на комментариях, некоторые ссылки от John Resig blog:

http://ejohn.org/blog/revised-javascript-dictionary-search/

http://ejohn.org/blog/jquery-livesearch/

Ответ 4

Функция ES2016: Array.prototype.includes без внешней библиотеки.

function autoComplete(Arr, Input) {
    return Arr.filter(e =>e.toLowerCase().includes(Input.toLowerCase()));
}

Codepen Demo

Ответ 5

Я исследовал это однажды вечером, и мое решение изначально было похоже на решение ES6 здесь, например:

return this.data.filter((option) => {
    return option.first_name
        .toString()
        .toLowerCase()
        .indexOf(this.searchTerms.toLowerCase()) >= 0
})

Но проблема в том, что он недостаточно надежен для фильтрации вложенных данных. Вы можете видеть, что он фильтрует this.data с такой структурой данных:

[
    { first_name: 'Bob', },
    { first_name: 'Sally', },
]

Вы можете видеть его фильтрацию на основе this.searchTerms после нижнего регистра как поискового термина, так и option.first_name, но он слишком жесткий для поиска option.user.first_name. Моя первоначальная попытка состояла в том, чтобы передать в поле для фильтрации, например:

this.field = 'user.first_name';

Но это включает в себя дикий, настраиваемый JavaScript для обработки чего-то вроде this.field.split('.') и динамическую генерацию функции фильтра.

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

Проверьте здесь: https://fusejs.io/

[редактировать заметку]: я понимаю, что этот вопрос не требует никакой внешней библиотеки, но я хочу оставить этот пост здесь, так как он предоставляет смежные значения. Это не предназначено, чтобы быть "решением".

Вот как я сейчас его использую:

import Fuse from 'fuse.js';

const options = {
    threshold: 0.3,
    minMatchCharLength: 2,
    keys: [this.field],
};

const fuse = new Fuse(this.data, options);

this.filteredData = fuse.search(this.searchTerms);

Чтобы лучше это понять, вам придется прочитать документацию по Fuse, но в целом вы можете видеть, что объект new Fuse() создается с использованием данных для фильтрации и параметров.

Часть keys: [this.field] важна, потому что там, где вы передаете ключи для поиска, вы можете передать их массив. Например, вы можете отфильтровать this.data по keys: ['user.first_name', 'user.friends.first_name'].

Я использую это в настоящее время в Vue JS, поэтому у меня есть вышеупомянутая логика внутри функции экземпляра watch, поэтому каждый раз, когда изменяется this.searchTerms, эта логика запускается и обновляет this.filteredData, который помещается в мой выпадающий список в моем компоненте автозаполнения.

Кроме того, извините, я только что понял, что этот вопрос специально говорит без внешней библиотеки, но я все равно опубликую его, потому что я нахожу этот вопрос каждый раз, когда делаю автозаполнение ES6 в Vue JS или React JS. Я думаю, что очень важно иметь строгое или нечеткое сопоставление и поддерживать произвольно вложенные данные. Основанный на пакетном анализаторе Webpack, fuse.js имеет размер 4,1 КБ в сжатом виде, поэтому он достаточно мал, поскольку может поддерживать "все" требования фильтрации на стороне клиента.

Если вы ограничены в своих возможностях использовать внешние библиотеки, рассмотрите мой первый пример кода. Это работает, если ваша структура данных статична, и вы можете легко изменить option.first_name на что-то вроде option[this.field], если вы хотите варьировать искомое поле (т.е. если ваши объекты всегда плоские).

Вы также можете варьировать список для поиска. Попробуйте что-то вроде этого:

const radicalFilter = ({ list, field, searchTerms }) => {
    return list.filter((option) => {
        return option[field]
            .toString()
            .toLowerCase()
            .indexOf(searchTerms.toLowerCase()) >= 0
    })
}

radicalFilter({
    list: [{ first_name: 'Bob' }, { first_name: 'Sally' }],
    field: 'first_name',
    searchTerms: 'bob',
})

Ответ 6

Я сделал это один раз, отправив запрос JSON на сервер и используя код Python для выполнения автозаполнения. Он был немного медленным, но он сохранил передачу тонны данных.