Описание на данный момент занимает 351КБ места (то, которое у вас), и в основном содержит повторяющиеся HTML-элементы. Храните только сами данные, без того, как они должны быть представлены. Данные в чистом виде легко обрабатывать, чем пытаться их вытащить из разметки! (jQuery с этим ужасно не справляется, для этого лучше подходит класс DOMParser, он для такого и предназначен)
Но всё-таки вот вариант с DOMParser...
function fnSearch(array, pattern) {
var parts = pattern.trim().toLowerCase().split(/\s+/);
var p = new DOMParser();
var s = Symbol.for("product description");
return array.filter(function(product) {
var description =
s in product ?
product[s] :
product[s] =
p .parseFromString(product.html, "text/html")
.body
.textContent
.toLowerCase()
.split(/\s+/)
;
return parts.every(function(part) {
return description.some(function(word) {
// return word === part;
return word.startsWith(part);
});
});
});
}
Оно ищет так, чтобы каждое искомое слово в описании начиналось на него! Если вам нужно, что каждое искомое слово присутствовало полностью в описании, то используйте
return word === part;. Я вам рекомендую использовать вариант (word.startsWith(part)), поскольку набрав только "nok" уже видно, что есть "nokia". Однако точное совпадение (word === part) предполагает, что пользователи полностью наберут "nokia", чтобы увидеть результаты "nokia". На самом же деле набрав только "nok", и увидев, что там ничего не появилось, пользователи скорей решат, что там нет того, о чём они думают, чем полностью будут вводить труднопроизносимые для них слова. Вариант (word.startsWith(part)) более интерактивный и подразумевает меньше усилии для достижения результата со стороны пользователя!
И ещё, если ничего не ввести, то (word === part) ничего не покажет, а (word.startsWith(part)) показывает всё! Поэтому вам нужна пошаговая *загрузка*, т. е., например показывайте первые 12 результатов, а остальные добавляются, например, при нажатии на кнопку в конце списка!
Если можно ничего не вводить и получать результаты, то можно добавить, например, ценовой фильтр. (Возможности безграничны!)
Сообщение от Alexko64
|
не возможно реализовать точный поиск
|
Вы можете комбинировать (word === part) и (word.startsWith(part)) и пусть пользователь сам выбирает, какой ему нужен поиск! (в примере ниже я показываю, как это сделать)
Также из вашего HTML можно извлечь чистые данные. Данные в чистом виде легко обрабатывать, чем пытаться их вытащить из разметки!
Получается 216КБ после замены на JSON без лишних пробелов и разметки (только чистые данные), что в свою очередь в за-gzip-ированном виде занимает 28КБ.
И уже на основе такого чистого JSON легко генерировать какую угодно разметку! Тогда не нужно использовать даже DOMParser!
Тогда эта функция поиска выглядит так...
function fnSearch(array, pattern) {
var parts = pattern.trim().toLowerCase().split(/\s+/);
return array.filter(function({ product }) {
var description = product.toLowerCase().split(/\s+/);
return parts.every(function(part) {
return description.some(function(word) {
// return word === part;
return word.startsWith(part);
});
});
});
}
Вот для примера перевёл ваши данные в чистый JSON, и написал маленькую функцию performSearch, которая запускает fnSearch и печатает результат...
Сам пример
https://codesandbox.io/s/nnkw1q7rvm?view=preview и код в песочнице
<iframe src="https://codesandbox.io/embed/nnkw1q7rvm?view=preview" style="width:100%; height:700px; border:0; border-radius: 4px; overflow:hidden;" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>
Пользователи вам не роботы извергающие точные запросы! Так что они вам туда ещё напишут "айфон" и "xaomi", так что вы можете улучшить свою программу, добавив... (подсказка: транслитерация, расстояние Левенштейна)