#javascript #jquery #html #filter
#javascript #jquery #HTML #Фильтр
Вопрос:
Я создал таблицу, но использую <div>
s вместо <tr>
s и <td>
s. вот пример:
<div class="tbl tbl1">
<div class="thead">
<div class="tr">
<div class="td colTitle" style="width: 120px"><span>Title</span></div>
<div class="td colLink" style="width: 190px"><span>Link</span></div>
<div class="td colSize numeric" style="width: 75px"><span>Size(MB)</span></div>
<div class="td colUploadDate" style="width: 75px"><span>UploadDate</span></div>
<div class="td colOpen" style="width: 50px; max-width: 50px;"><span>Show</span></div>
</div>
<div class="tr">
<div class="td colTitle">
<input type="text" class="Filter" />
</div>
<div class="td colLink">
<input type="text" class="Filter" />
</div>
<div class="td colSize">
<input type="text" class="Filter" />
</div>
<div class="td colUploadDate">
<input type="text" class="Filter" />
</div>
<div class="td colOpen">
</div>
</div>
</div>
<div class="tbody">
</div>
</div>
Я заполню tbody
часть операциями на стороне сервера.
Я использую приведенные ниже коды для фильтрации моих строк на основе значений, введенных во входных данных фильтра.
$(".Filter").on('input', function () {
filterGrid();
$(".rowCount").val($(".tbody .tr:visible").length);
});
function filterGrid() {
$('.tbody .tr').each(function () {
var v = 1;
var x = $(this);
$(".thead .Filter[value!='']").each(function () {
var i = $(this).parent(".td").index();
if (x.children(".td:eq(" i ")").html().indexOf($(this).val()) == -1) {
v = 0;
x.hide();
return false;
}
});
if (v == 1) {
x.show();
}
});
}
Мой код отлично работает, когда у меня есть несколько строк, но когда количество загруженных строк увеличивается, для выполнения операции фильтрации требуется больше времени.
когда я ввожу первую букву, я не могу ввести вторую букву до окончания фильтрации на основе первой буквы. могу ли я принудительно применить javascript для прерывания операции и запуска новой при вводе?
ниже приведен пример моей таблицы
Комментарии:
1. Можете ли вы опубликовать несколько примеров строк внутри
tbody
, чтобы мы могли видеть, на что похожа структура?2. @CertainPerformance Я прикрепил фотографию, показывающую мою таблицу, содержащую некоторые данные.
3. Первое, что вам следует сделать, это оптимизировать ваш код. В настоящее время у вас есть неэффективный код с большим объемом jQuery и ужасный алгоритм (который, например, не кэширует результаты и пересчитывает только столбец, значение фильтра которого изменилось). Если это не помогает и у вас действительно есть тысячи строк, вам нужно будет выполнить цикл асинхронно и прерваться, если есть новый ввод.
4. Можете ли вы опубликовать фактический HTML ? Картинки не очень полезны, они не показывают структуру HTML
5. пример строки: <div class=»tr» idattachment=»1″><div class=»td colTitle» style=»width: 120px;»>FirstFile</div><div class=»td colLink» style=»width: 190px;»>uf1_1.png</div><div class=»td colSize» style=»width: 75px;»>0.11</ div><div class=»td colUploadDate» style=»width: 75px;»>1397/12/13</div><div class=»td colOpen» style=»width: 50px;»><a class=»link» href=»uploads/uf1_1.png»>Открыть</a></div></div>
Ответ №1:
У вас есть довольно много операций jQuery, которые, будучи объединены во многих строках, могут занять немалое количество времени. Вместо того, чтобы создавать множество коллекций jQuery (которые требуют определенных накладных расходов) и пересчитывать искомый индекс на каждой итерации, рассмотрите возможность использования вместо этого ванильного Javascript, который гораздо более легкий. Вы также можете заранее создать массив значений фильтра и связанный с ними индекс, чтобы вам не приходилось перемещаться по DOM, чтобы находить их на каждой итерации:
$(".Filter").on('input', function() {
$(".rowCount").val(filterGrid());
});
function filterGrid() {
const values = Array.from(
document.querySelectorAll('.thead .Filter'),
elm => elm.value
);
let rowsShown = 0;
document.querySelectorAll('.tbody .tr').forEach((tr) => {
const tds = tr.querySelectorAll('.td');
const noMatch = values.some((value, i) => {
if (!value) {
return;
}
const td = tds[i];
return !td.innerHTML.includes(value);
});
if (noMatch) {
tr.style.display = 'none';
} else {
tr.style.display = 'block';
rowsShown ;
}
});
return rowsShown;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
RowCount: <span class="rowCount">1</span>
<div class="tbl tbl1">
<div class="thead">
<div class="tr">
<div class="td colTitle" style="width: 120px"><span>Title</span></div>
<div class="td colLink" style="width: 190px"><span>Link</span></div>
<div class="td colSize numeric" style="width: 75px"><span>Size(MB)</span></div>
<div class="td colUploadDate" style="width: 75px"><span>UploadDate</span></div>
<div class="td colOpen" style="width: 50px; max-width: 50px;"><span>Show</span></div>
</div>
<div class="tr">
<div class="td colTitle">
<input type="text" class="Filter" />
</div>
<div class="td colLink">
<input type="text" class="Filter" />
</div>
<div class="td colSize">
<input type="text" class="Filter" />
</div>
<div class="td colUploadDate">
<input type="text" class="Filter" />
</div>
<div class="td colOpen">
</div>
</div>
</div>
<div class="tbody">
<div class="tr" idattachment="1">
<div class="td colTitle" style="width: 120px;">FirstFile</div>
<div class="td colLink" style="width: 190px;">uf1_1.png</div>
<div class="td colSize" style="width: 75px;">0.11</div>
<div class="td colUploadDate" style="width: 75px;">1397/12/13</div>
<div class="td colOpen" style="width: 50px;"><a class="link" href="uploads/uf1_1.png">Open</a></div>
</div>
</div>
</div>
Если это недостаточно быстро, вы можете использовать for
циклы вместо методов массива, что немного ускорит работу (хотя и будет сложнее для чтения).
Если у вас огромное количество строк в .tbody
, и это все еще недостаточно быстро, то вы могли бы рассмотреть возможность добавления debouncer в input
listener, чтобы он filterGrid
вызывался только, скажем, через 200 мс после ввода последнего символа, так что большая операция выполняется только тогда, когда у вас есть хотя бы немного уверенности в том, что только что введенный символ может быть последним, который пользователь хочет ввести (вместо запуска filterGrid
после каждого введенного символа):
let filterTimeout;
$(".Filter").on('input', function() {
clearTimeout(filterTimeout);
filterTimeout = setTimeout(() => {
$(".rowCount").val(filterGrid());
}, 200);
});
Комментарии:
1. Также верните количество совпадений из
filterGrid
вместо этого ужасного$(".tbody .tr:visible").length
2. Я бы сохранил
tr.style.display = noMatch ? 'none' : 'block';
и сделалrowsShown = !noMatch;
. Но в любом случае проголосуйте за!3. Отлично, это действительно эффективно.