如何使过滤函数进一步缩小过滤范围,而不重新加载数据?

6 浏览
0 Comments

如何使过滤函数进一步缩小过滤范围,而不重新加载数据?

我有一个包含产品型号的数据集,我想通过减少数据集来使用数组过滤器进行过滤。我有一些单选输入框,它们执行过滤函数以减少数据集,但每次点击事件都会重置数据。

我希望它们能够检查是否已选择了一个单选按钮,并从那里进一步减少数据。

这是一个简要的说明:我有这样的数据:

const stratPickups = {

"Model 1": {

name: "Clean Model",

design: "Single Coil",

output: 4,

look: "traditional"

},

"Model 2": {

name: "Balanced Model",

design: "Single Coil",

output: 5,

look: "traditional"

},

"Model 3": {

name: "Balanced Model 2",

design: "Single Coil",

output: 6,

look: "traditional"

},

"Model 4": {

name: "High Output Model",

design: "Single Coil",

output: 8,

look: "traditional"

},

}

我还有一个change事件,像这样加载数据:

if (e.target.value === "strat") {

data = Object.values(stratPickups);

refreshView(data);

}

这调用了一个名为refreshView(data)的函数,它以这样的方式填充屏幕上的“卡片”:

const refreshView = (dataSet) => {

dataSet.forEach((p) => {

output.innerHTML += `

${p.name}


Specs:

Output: ${p.output}

Description: ${p.description}

See Product

`;

});

};

最后,我有一些单选输入框,它们应该基于外观和设计过滤数据数组。它看起来像这样:

const filterByTrad = () => {

if (pickupType.value === "strat") {

data = Object.values(stratPickups).filter((p) => p.look === "traditional");

} else if (pickupType.value === "tele") {

data = Object.values(telePickups).filter((p) => p.look === "traditional");

}

let traditionalData = data;

refreshView(traditionalData) // 使用过滤后的数据刷新视图

}

const filterByUni = () => {

if (pickupType.value === "strat") {

data = Object.values(stratPickups).filter((p) => p.look === "unique");

} else if (pickupType.value === "tele") {

data = Object.values(telePickups).filter((p) => p.look === "unique");

} ...

let uniqueData = data;

refreshView(uniqueData) // 使用过滤后的数据刷新视图

}

const filterBySingleCoil = () => {

if (pickupType.value === "strat") {

data = Object.values(stratPickups).filter((p) => p.design === "single-coil");

} else if (pickupType.value === "tele") {

data = Object.values(telePickups).filter((p) => p.design === "single-coil");

}

let singleCoilData = data

refreshView(singleCoilData)

}

const filterByHumCancelling = () => {

if (pickupType.value === "strat") {

data = Object.values(stratPickups).filter((p) => p.design === "hc");

} else if (pickupType.value === "tele") {

data = Object.values(telePickups).filter((p) => p.design === "hc");

}

let hcData = data

refreshView(hcData)

}

traditionalAppearance.addEventListener("click", filterByTrad);

uniqueAppearance.addEventListener("click", filterByUni);

singleCoil.addEventListener("click", filterBySingleCoil);

hc.addEventListener("click", filterByHumCancelling);

问题:上述方法可以正常工作,但每次点击时,它都会加载过滤后的数据集。它不会考虑是否选择了其他复选框并从那里进行过滤。我的问题是,您会如何设计这个过滤函数以考虑这些因素?

这里有一个CodePen:CodePen

要重现:

  1. 从Pickup Type中选择Stratocaster Pickups
  2. 点击“Unique Appearance”进行更多过滤,注意结果
  3. 从第二组过滤器中点击“Single Coil”,注意数据集被重新加载。

更新

我创建了一个名为filters的对象:

const filters = {

traditional: false,

unique: false,

singleCoil: false,

humCancelling: false,

};

还添加了一个名为addEventListeners()的函数,它控制每个对象键的true / false值。

const addEventListeners = () => {

traditionalAppearance.addEventListener("click", function () {

filters.traditional = this.checked;

if (this.checked == true) {

filterByTrad(data);

}

});

uniqueAppearance.addEventListener("click", function () {

filters.unique = this.checked;

if (this.checked == true) {

filterByUni(data);

}

});

singleCoil.addEventListener("click", function () {

filters.singleCoil = this.checked;

if (this.checked == true) {

filterBysingleCoil(data);

}

});

hc.addEventListener("click", function () {

filters.humCancelling = this.checked;

if (this.checked == true) {

filterByHumCancelling(data);

}

});

};

addEventListeners();

最后,我将我的函数改为Pure函数,如下所示:

const filterByTrad = (array) => {

data = Object.values(array).filter((p) => p.look === "traditional");

refreshWithFilters(data);

return data;

};

const filterByUni = (array) => {

data = Object.values(array).filter((p) => p.look === "unique");

refreshWithFilters(data);

};

const filterBysingleCoil = (array) => {

data = Object.values(array).filter((p) => p.design === "single-coil");

refreshWithFilters(data);

};

const filterByHumCancelling = (array) => {

data = Object.values(array).filter((p) => p.design === "hc");

refreshWithFilters(data);

};

const refreshWithFilters = (data) => {

refreshView(data);

};

现在,我正在努力完成下一步,基于下面的评论。您会有什么不同的做法吗?

0
0 Comments

如何让过滤函数进一步筛选,而不是重新加载数据?

问题出现的原因是过滤函数具有刷新的副作用,因此它们不是纯粹的。输入是一个数组,输出是一个经过过滤的数组,不涉及任何复杂操作。

解决方法是将过滤函数拆分为纯函数,它们只接受一个列表并返回应用了该过滤器的列表。然后,创建一个"refreshWithFilters"方法,该方法将选择正确的电吉他/斯特拉特对象,然后遍历过滤器状态对象,并应用所有正确的过滤器,最后刷新视图。然后,输入事件侦听器只需切换过滤器状态对象中与其关联的布尔值,并调用该通用过滤器+刷新方法。

具体的解决方法如下:

首先,存储一个数组/对象,用于存储输入状态(复选框而不是单选按钮,以便它们不是互斥的),例如:

let filters = {single: false, singleCoil: false, unique: true ...}

然后,将过滤函数拆分为纯函数,只接受一个列表,并返回应用了该过滤器的列表,例如:

const filterByTrad = (array) => Object.values(array).filter((p) => p.look === "traditional");
const filterByUni = (array) => Object.values(array).filter((p) => p.look === "unique");

接下来,为事件侦听器创建相应的函数,这些函数将切换其关联布尔值在过滤器状态对象中的状态,并调用共享的过滤器+刷新方法,例如:

traditionalAppearance.addEventListener("click", function () {
    filters.traditional = this.checked;
    refreshWithFilters()
});
uniqueAppearance.addEventListener("click", function () {
    filters.unique = this.checked;
    refreshWithFilters()
});

最后,创建一个"refreshWithFilters"函数,该函数获取原始数据,应用所有过滤器以确保它们都被应用,然后刷新数据,例如:

const refreshWithFilters = () => {
  let data = (pickupType.value === "strat") ? stratPickups : telePickups;
  data = Object.values(data);
  if (filters.traditional) data = filterByTrad(data);
  if (filters.unique) data = filterByUni (data);
  refreshView(data);
}

这样,你就有了一组可分离、可测试的过滤器,在一个大的、不重复的共享方法中有选择地应用这些过滤器,该方法与所有点击处理程序关联。

至于复选框和单选按钮的选择,出于无障碍性和用户体验的原因,应遵循惯例:单选按钮只能选择其中的一个选项,复选框可以选择多个选项。

在你的最初问题中,你说"如果已经选择了一个单选按钮,我希望它们进行检查,并进一步减少数据。"这听起来像是连续使用多个过滤器?

如果单选按钮被分组,当设置了组中的其他单选按钮时,它们将自动取消选择,这样可以减少你在代码中的工作量!在这里可以查看如何设置:[stackoverflow.com/questions/28543752/…](https://stackoverflow.com/questions/28543752)

这种方法可能有效,但如果你启用了单线圈,可能需要禁用蜂鸣器,你可以在各个更改处理程序中完成这些操作。在"refreshWithFilters"的顶部添加一个 console.log(filters),看看这是否适用于单选按钮。

希望这能帮到你!

0