代码过于复杂,难以理解。其一,这一点
var v = this.value;
if (selectedFilters.indexOf(v) === -1 && v)
selectedFilters.push(v);
只是为了避免数组中出现重复。这意味着它更像是一个set https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set,这是一种本身避免重复的数据结构。如果你这样做selectedFilters = new Set()
,那么整个块可以替换为selectedFilters.add(this.value);
查询“该类别是否包含在所选过滤器中”也可以从selectedFilters.indexOf(cat) === -1
to selectedFilters.has(cat)
。这样,代码就已经开始更加匹配所需的行为。
此外,单字母变量也应该被废除,并由解释性名称代替。代码还应该有更多注释来解释发生了什么。
然后,能够从菜单和复选框中选择过滤器会造成混乱。我不确定这应该如何工作,所以我只是更改了代码,以便将它们全部分组在一起:当通过复选框或菜单选择过滤器时,过滤器处于活动状态。
最后还有一个问题,即“允许的 NSFW”与其他类别的过滤并不完全相同。因此,我只是为它创建了一个单独的变量,并将其从过滤器中删除。最后我添加了一个额外的调用filterFunc()
这样事情就开始被过滤(而不是等待过滤器复选框/菜单的第一次更改)。这就是最终结果。
EDIT:更新了“仅限 MVP”复选框。
EDIT 2:不要让“MVP”复选框显示带有 MVP 标签的所有内容。
EDIT 3:翻转条件以显示项目;他们现在需要所有标签。旧代码被注释掉,以便任何人都可以根据需要自行恢复此开关。
var $filterCheckboxes = $('input[type="checkbox"]');
var $filtermenus = $('.grid1');
// Return the intersection of setA and setB.
// Source: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set
function intersection(setA, setB) {
let _intersection = new Set()
for (let elem of setB) {
if (setA.has(elem)) {
_intersection.add(elem)
}
}
return _intersection
}
function isSuperset(set, subset) {
for (let elem of subset) {
if (!set.has(elem)) {
return false
}
}
return true
}
function filterFunc() {
var selectedFilters = new Set();
// Gather tags from the menus.
$filtermenus.find(":selected").each(function () {
if (this.value)
selectedFilters.add(this.value);
});
// Gather tags from the checkboxes.
$filterCheckboxes.filter(':checked').each(function () {
if (this.value)
selectedFilters.add(this.value);
});
console.log("selected filters:", [...selectedFilters]);
let mayShowNSFW = selectedFilters.has("NSFW");
selectedFilters.delete("NSFW");
let mustShowMVPOnly = selectedFilters.has("MVP");
selectedFilters.delete("MVP");
$('.filterDiv')
.hide()
.filter(
// Returns 'true' to show items, 'false' to hide them.
function (_, element) {
let itemCats = new Set($(element).data('category').split(' '));
// If the item has tag 'showAll', always show it.
if (itemCats.has("showAll"))
return true;
// If item is NSFW but that's not in the filters, hide the item
// regardless of other tags.
if (itemCats.has("NSFW") && !mayShowNSFW)
return false;
if (mustShowMVPOnly && !itemCats.has("MVP"))
return false;
// If there are no filters at all, just show everything.
if (selectedFilters.size == 0)
return true;
// If this item has all the tags, show it:
return isSuperset(itemCats, selectedFilters);
// If this item has any of the tags, show it:
// return intersection(selectedFilters, itemCats).size > 0;
})
.show();
}
$filterCheckboxes.on('change', filterFunc);
$('select').on('change', filterFunc);
filterFunc();