Вы используете filter()
для переключения каждого элемента в зависимости от состояния, например each()
. Но одним из преимуществ filter()
является то, что вы можете вернуть уменьшенный выбор и сосчитать содержащиеся в нем элементы. Это значение может определять, должно ли отображаться сообщение «нет совпадения».
... метод .filter () создает новый объект jQuery из подмножества соответствующих элементов. Поставляемый селектор проверяется по каждому элементу; все элементы, соответствующие селектору, будут включены в результат. - фильтр () .
Для каждого элемента, если функция возвращает true (или «истинное» значение), элемент будет включен в отфильтрованный набор; в противном случае это будет исключено. - Использование функции фильтра
Таким образом, вместо переключения элементов непосредственно из вызова фильтра, рассмотрите возможность возврата логического показателя того, является ли текущий элемент совпадающим. Сохраните полученный отфильтрованный выбор в переменной. После фильтрации вы можете переключить этот выбор в целом:
var $filtered = $items.filter(function() {
return $(this).text().indexOf(value) > -1;
});
$items.toggle(false);
$filtered.toggle(true);
Это скрывает все элементы, а затем показывает только отфильтрованные элементы.
Вы могли бы даже рассмотреть некоторую анимацию исчезновения:
$items.hide(250);
$filtered.stop(true,false).show(250);
Затем вы можете ссылаться на отфильтрованный выбор length
.
Если оно равно нулю, показать сообщение «not found»:
var hasMatches = $filtered.length;
if (hasMatches) {
// there were matches.
} else {
// no matches.
}
Вы также можете передать селектор в фильтр. Селектор jQuery :contains()
выбирает «все элементы, которые содержат указанный текст», что делает хороший выбор.
Рабочий пример:
var $items = $('.item');
var $none = $('#none');
var fade = 250;
function filterContent() {
// get word from value of clicked button.
var word = this.value;
// hide items; filter; show filtered; count matches
var hasMatches = $items
.hide(fade)
.filter(':contains(' + word + ')')
.stop(true, false)
.show(fade)
.length;
// if no matches, show message.
if (hasMatches) {
$none.hide(fade);
} else {
$none.show(fade);
}
}
$('button').on('click', filterContent);
#none {
display: none;
color: darkred;
}
#buttons {
margin: 1em 0 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="item">Here is some text.</div>
<div class="item">Here is some other text.</div>
<div class="item">Here is some other different text.</div>
<div class="item">Here is something else.</div>
<div class="item">Here is some additional text.</div>
<div id="none">No matches found.</div>
<nav id="buttons">
<button type="button" value="">all</button>
<button type="button" value="text">text</button>
<button type="button" value="other">other</button>
<button type="button" value="additional">additional</button>
<button type="button" value="bazooka">bazooka</button>
</nav>
Другой способ:
Если вы предпочитаете, вы можете переключаться внутри фильтра, пока вы все еще возвращаете логическое состояние из функции. Я предлагаю сделать отдельную функцию для перехода на фильтр. В этом случае toggleItem()
определяет состояние элемента (соответствует или не соответствует), переключает элемент в соответствии с этим состоянием и возвращает состояние.
var $items = $('.item');
var $none = $('#none');
function toggleItem(word) {
return function(k, el) {
var $item = $(el);
var state = $item.text().indexOf(word) > -1;
$item.toggle(state);
return state;
}
}
function filterContent() {
// get word from value of clicked button.
var word = this.value;
// filter while toggling and count result.
var hasMatches = $items
.filter(toggleItem(word))
.length;
// if no matches, show message.
$none.toggle(!hasMatches);
}
$('button').on('click', filterContent);
#none {
display: none;
color: darkred;
}
#buttons {
margin: 1em 0 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="item">Here is some text.</div>
<div class="item">Here is some other text.</div>
<div class="item">Here is some other different text.</div>
<div class="item">Here is something else.</div>
<div class="item">Here is some additional text.</div>
<div id="none">No matches found.</div>
<div id="buttons">
<button type="button" value="">all</button>
<button type="button" value="text">text</button>
<button type="button" value="other">other</button>
<button type="button" value="additional">additional</button>
<button type="button" value="bazooka">bazooka</button>
</div>
На мой взгляд, это немного сложнее для чтения и не так ясно, как цепочечные команды "скрыть, отфильтровать, показать, длина", но это в некоторой степени вопрос стиля. Вы можете видеть, что есть много способов испечь этот пирог!
Этот довольно короткий и сладкий:
var $none = $("#none");
var $items = $(".item");
$("button").click(function() {
var value = $(this).data('value');
$items.each(function() {
$(this).toggle($(this).text().indexOf(value) > -1);
});
$none.toggle(!$items.filter(':visible').length);
});
#none {
display: none;
color: darkred;
}
#buttons {
margin: 1em 0 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="item">Here is some text.</div>
<div class="item">Here is some other text.</div>
<div class="item">Here is some other different text.</div>
<div class="item">Here is something else.</div>
<div class="item">Here is some additional text.</div>
<div id="none">No matches found.</div>
<nav id="buttons">
<button type="button" data-value="">all</button>
<button type="button" data-value="text">text</button>
<button type="button" data-value="other">other</button>
<button type="button" data-value="additional">additional</button>
<button type="button" data-value="bazooka">bazooka</button>
</nav>