Фильтрация | JavaScript

На сайте redotheweb.com показано интересное решение фильтрации данных. Его я внедрила в список високосных лет.

Задумка основана на использовании псевдоклассов и селекторов CSS. Благодаря тому, что скрипт изменяет только один тег style, а не все элементы списка, увеличивается скорость поиска.

<style>
.contacts li {
 display: block;
 margin: 10px;
 padding: 10px;
 background-color: rgb(220, 234, 244);
}
.contacts li :before {
 font-weight: 900;
}
.contacts li :nth-of-type(1):before {
 content: "Имя: ";
}
.contacts li :nth-of-type(2):before {
 content: "Фамилия: ";
}
.contacts li :nth-of-type(3):before {
 content: "email: ";
}
.contacts li :nth-of-type(4):before {
 content: "телефон: ";
}
</style>

<input type="text" placeholder="поиск" id="search">
<style id="search-style"></style>
<ul class="contacts">
  <li data-index="марьяивановаmar.ivanova@yandex.ru89270000000">
    <div>Марья</div>
    <div>Иванова</div>
    <div>mar.ivanova@yandex.ru</div>
    <div>89270000000</div>
  <li data-index="иванпетровivan.petriv@mail.ru89031111111">
    <div>Иван</div>
    <div>Петров</div>
    <div>ivan.petriv@mail.ru</div>
    <div>89031111111</div>
  <li data-index="фёдорсидоровsidorov@mail.ru8172222222">
    <div>Фёдор</div>
    <div>Сидоров</div>
    <div>sidorov@mail.ru</div>
    <div>8172222222</div>
  <li data-index="людмиласнегирёваsnegir@gmail.com333-33-33">
    <div>Людмила</div>
    <div>Снегирёва</div>
    <div>snegir@gmail.com</div>
    <div>333-33-33</div>
</ul>

<script>
var searchStyle = document.getElementById('search-style');
document.getElementById('search').addEventListener('input', function() {
  if (!this.value) {
    searchStyle.innerHTML = '';
    return;
  }
  searchStyle.innerHTML = '.contacts li:not([data-index*="' + this.value.toLowerCase() + '"]) { display: none; }';
});
</script>

В data-index заносятся искомые данные с маленькой (строчной) буквы. При введении, скажем, буквы м в теге style появится запись

.contacts li:not([data-index*="м"]) { display: none; }
. Она означает, что если li в data-index не содержит буквы м, то такой li нужно удалить.

  • Марья
    Иванова
    mar.ivanova@yandex.ru
    89270000000
  • Иван
    Петров
    ivan.petriv@mail.ru
    89031111111
  • Фёдор
    Сидоров
    sidorov@mail.ru
    8172222222
  • Людмила
    Снегирёва
    snegir@gmail.com
    333-33-33

В списоке високосных лет этот же скрипт у меня выглядит как:

<ul data-index="1" class="spisokGod">
  <li>
    <ol data-index="15">
      <li data-index="1584">1584
      <li data-index="1588">1588
    </ol>
  <li>
    <ol data-index="16">
      <li data-index="1600">1600
      <li data-index="1604">1604
    </ol>
  </li>
</ul>

<ul data-index="2" class="spisokGod">
  <li>
    <ol data-index="20">
      <li data-index="2000">2000
      <li data-index="2004">2004
    </ol>
  <li>
    <ol data-index="21">
      <li data-index="2104">2104
      <li data-index="2108">2108
    </ol>
  </li>
</ul>

<script>
var searchStyle = document.getElementById('search-style');
document.getElementById('search').addEventListener('input', function() {
  if (!this.value) {
    searchStyle.innerHTML = '';
    return;
  }
  searchStyle.innerHTML = '.spisokGod ol li:not([data-index^="' + this.value + '"]), .spisokGod ol:not([data-index^="' + this.value.substr(0, 2) + '"]), .spisokGod:not([data-index^="' + this.value.substr(0, 1) + '"]) { display: none;}';

});
</script>

Здесь скрываются списки, которые не начинаются с цифр, вводимых пользователями в поле поиска. При проверке 2000 года в теге style можно увидеть:

.spisokGod ol li:not([data-index^="200"]),
.spisokGod ol:not([data-index^="20"]),
.spisokGod:not([data-index^="2"]) { display: none;}

Обрезание до нужного знака делает .substr(0, 1).

в f t
наверх ↑

16 комментариев:

Максим
Здрасьте. Что мне изменить в скрипте, чтобы бы он учитывал пробелы случайные и не одно слово или часть, а несколько слов через пробел допустим, пример: [Фёдор Людмила] , и выводится две записи разные с фёдором и людмилой!

Спасибо заранее!
NMitra
Здравствуйте. HTML тот же. Скрипт:

var searchStyle = document.getElementById('search-style');
document.getElementById('search').addEventListener('input', function() {
if (!this.value) {
searchStyle.innerHTML = '';
return;
}
var raz = this.value.split(/\s/, 1).join('\s'),
dva = this.value.replace(/.*?\s/g, '').split(/\s/, 1).join('\s');
searchStyle.innerHTML = '.contacts li:not([data-index*="' + raz.toLowerCase() + '"]):not([data-index*="' + dva.toLowerCase() + '"]) { display: none; }';
});
Максим
Всё работает на десктопе(компьютере), а в мобильной версии (резиновой) на андроиде и на виндофоне, почему то два слова не ловит, очищает список полностью. Хех :)
NMitra
Попробуйте стиль без скрипта:

.contacts li:not([data-index*="иван"]):not([data-index*="фёдор"]) { display: none; }

Если работает, то нужно скрипт разбирать, если нет, то на этих устройствах не полная поддержка CSS селекторов
Максим
Ага стиль отдельно робит! Что-то со скриптом)
NMitra
После
dva = this.value.replace(/.*?\s/g, '').split(/\s/, 1).join('\s');
напиши
alert(dva);

Понимает?
Макс
Ага. Алертится !
NMitra
Даже когда вводить в input два слова?

Я в ступоре, что там в строке
searchStyle.innerHTML = '.contacts li:not([data-index*="' + raz.toLowerCase() + '"]):not([data-index*="' + dva.toLowerCase() + '"]) { display: none; }';
может не нравится?
Макс
О боже заработало. Всё так и оставил и вдруг заробило. Сделал другую форму с поиском, но ведь ничего нового не поменялось. Только оформление. Мб что-то глючило. Спасибо за помощь! Вы супер кодер) Я совсем слегка яву изучал только.
Вот эти тонкости форматирования просто не понимаю пока, не дошел... (/.*?\s/g, '').split(/\s/, 1).join('\s') ...
Ещё бы хотелось чтоб учитывались первые пробелы, а точнее не учитывались, типа случайно ввёл пробел и дальше пишешь.
NMitra
Регулярные выражения лучше знать, они есть во многих языках программирования, даже в Аналитикс http://shpargalkablog.ru/2013/07/replace.html

var searchStyle = document.getElementById('search-style');
document.getElementById('search').addEventListener('input', function() {
if (!this.value) {
searchStyle.innerHTML = '';
return;
}
this.value = this.value.replace(/^\s/g, '');
if (this.value) {
var raz = this.value.split(/\s/, 1).join('\s'),
dva = this.value.replace(/.*?\s/g, '').split(/\s/, 1).join('\s');
searchStyle.innerHTML = '.contacts li:not([data-index*="' + raz.toLowerCase() + '"]):not([data-index*="' + dva.toLowerCase() + '"]) { display: none; }';
}
});
Макс
это опять я ! а если ничего не нашлось типа not сработал на все li , то как в этом случае допустим открыть какойто div блок по id с контентом "По вашему запросу ничего не найдено", вроде всё так элементарно по идее! Может как-то проверить на display == none ? Но ведь надо все элементы li проверить. Или может какой-то соседний элемент к общему ul включить , тоже с data-index, типа присвоить ему везде 1 типа когда во всех li что-то есть, или 0 когда нет.......брррр
NMitra
После
<style id="search-style"></style>
добавить
<div id="search-div">По вашему запросу ничего не найдено</div>

В CSS добавить
#search-div {
display: none;
}

Скрипт будет выглядеть

var searchStyle = document.getElementById('search-style');
document.getElementById('search').addEventListener('input', function() {
if (!this.value) {
searchStyle.innerHTML = '';
return;
}
searchStyle.innerHTML = '.contacts li:not([data-index*="' + this.value.toLowerCase() + '"]) { display: none; }';
var li = document.querySelectorAll('.contacts li'),
count = 0,
div = document.getElementById('search-div');
for (var i = 0; i < li.length; i++) {
if (getComputedStyle(li[i], '').display == 'none') {count += 1;}
}
if (count == li.length) {div.style.display = 'block'} else {div.style.display = 'none'}
});
NMitra
Считаем li, которые имеет display: none; Если их число совпадает с количеством li, то показываем невидимый блок.
Макс
Абалдеть! Вы БОГиня! =) до querySelector и getComputed я бы через 100 лет дошёл и понял для чего они))) Спасибо! Не знаю как и отблагодарить :)
Макс
Спустя время я обучился регуляркам :)
Вот вариант поиска с любым кол-вом слов и предварительным поиском на сплошные пробелы!
if (this.value && this.value.replace(/\s/g,'') != '') {
var words_all = this.value.replace(/ +/g, ' ').replace(/^\s/g, '');
var words_arr = words_all.split(/\s/);
var words_hide = '';
for (var i = 0; i < words_arr.length; i++) {
words_hide = words_hide + ':not([data-index*="'+words_arr[i].toLowerCase()+'"])';
}
words_hide = words_hide.replace(/^:/, '')
searchLeftCh.innerHTML = '#li_left_ch > li:'+words_hide+' {display: none;}';
searchRightCh.innerHTML = '#li_right_ch > li:'+words_hide+' {display: none;}';
searchLeftChBottom.innerHTML = '#li_left_ch_bottom > li:'+words_hide+' {display: none;}';
searchRightChBottom.innerHTML = '#li_right_ch_bottom > li:'+words_hide+' {display: none;}';
}
NMitra
Благодарю, регулярки - это вещь хорошая :)