使用 3 层菜单过滤结果列表

我有 3 个单独的菜单。

如果从该特定菜单中未选择任何内容,则它们都默认为“全部”。菜单项是过滤器,您可以从每个菜单中选择任意数量的过滤器。当点击过滤器时,这将构建 3 个包含所选项目的数组(请参见下文)。每个菜单中的过滤器都链接或包含到其他菜单,因此结果必须满足所有选定的过滤器,否则它会被禁用类。

我已经成功编写了 JS 来处理每个菜单的行为,因此使用 css 类突出显示选定的菜单项/过滤器。所以这一切都很好。

我遇到的问题是当我尝试过滤结果时。

当它们被单击时,它们会填充来自菜单过滤器的值,如果单击过滤器两次,则该项目将从数组中删除。

随着这些数组的变化,我正在调用一个函数来更新结果。

所以上面的更新函数只有在所有数组都有项目时才有效。所以我开始向上述条件添加进一步的逻辑,开始检查每个数组是否有项目,如果他们没有忽略它们,只是根据其他的过滤。显然,这会导致有进一步的逻辑来检查 3 个数组中的 2 个是否为空,等等。我觉得必须有更好的方法来做到这一点,而无需数十个嵌套的 if else 语句。也许我需要从完全不同的方式接近。

非常感谢任何帮助。谢谢。


慕田峪7331174
浏览 194回答 1
1回答

牧羊人nacy

在我添加我的解决方案之前,我必须感谢@ffriend和他的函数来找出两个或多个数组中的所有组合(为此给他+1 ;)):Finding All Combinations (Cartesian product) of JavaScript array values这个功能非常有用,我在我的解决方案中使用了。这是针对您的问题的不同方法,因此我当然必须更改您的 HTML 和 jQuery。首先是HTML。为了创建与您相同的过滤器系统,我决定只使用没有任何特定属性的类:<div class="results">&nbsp; &nbsp;<div class="Series-1 Body-1 Style-1">Result 1</div>&nbsp; &nbsp;<div class="Series-1 Body-1 Style-1">Result 2</div>&nbsp; &nbsp;<div class="Series-2 Body-2 Style-2">Result 3</div>&nbsp; &nbsp;<div class="Series-2 Body-1 Style-2">Result 4</div>&nbsp; &nbsp;<div class="Series-3 Body-1 Style-1">Result 5</div>&nbsp; &nbsp;<div class="Series-3 Body-1 Style-1">Result 6</div>&nbsp; &nbsp;<div class="Series-3 Body-2 Style-2">Result 7</div>&nbsp; &nbsp;<div class="Series-2 Body-1 Style-3">Result 8</div></div>...我创建了与所有导航列表的关系(也使用dot)<ul class="nav" data-obj="series">&nbsp; <li data-el="*" class="selected">All</li>&nbsp; <li data-el=".Series-1">Series 1</li>&nbsp; <li data-el=".Series-2">Series 2</li>&nbsp; <li data-el=".Series-3">Series 3</li></ul><ul class="nav" data-obj="body">&nbsp; <li data-el="*" class="selected">All</li>&nbsp; <li data-el=".Body-1">Body 1</li>&nbsp; <li data-el=".Body-2">Body 2</li>&nbsp; <li data-el=".Body-3">Body 3</li></ul><ul class="nav" data-obj="style">&nbsp; <li data-el="*" class="selected">All</li>&nbsp; <li data-el=".Style-1">Style 1</li>&nbsp; <li data-el=".Style-2">Style 2</li>&nbsp; <li data-el=".Style-3">Style 3</li></ul>在您的 CSS 中,我只删除了.disabled该类,因为我使用 jQuery 来做到这一点。现在是javascript。我已经评论了我认为重要的部分,以试图澄清所有步骤:/* I created one js object instead of 3 arrays, 'cause it is more simple to handle after in one general function */var results = {&nbsp; series:[],&nbsp; body:[],&nbsp; style:[]};/* put the results containet in a variable */var container=$(".results");$(".nav li").on('click', function(){&nbsp; /*this is the general function that works for all your clicks */&nbsp;&nbsp;&nbsp; /*set a few of variables */&nbsp; var $this=$(this);&nbsp; var parent=$this.parent();&nbsp; var parentObj=$this.parent().data("obj");&nbsp; var myClass=$this.data("el");&nbsp; var control=[]; /*this is an empty array that will set with your different classes*/&nbsp; if(myClass==="*") {&nbsp; &nbsp; /*click on first li*/&nbsp; &nbsp; if (!$this.hasClass("selected")) {&nbsp; &nbsp; &nbsp; &nbsp; /*do something if it didin't have the selected class*/&nbsp; &nbsp; &nbsp; $("li", parent).removeClass("selected"); /*remove selected classes from all li in my parent ul*/&nbsp; &nbsp; &nbsp; $this.addClass("selected");&nbsp; &nbsp; &nbsp; results[parentObj]=[];/* empty my associative object: series, body or style */&nbsp; &nbsp; }&nbsp; } else {&nbsp; &nbsp; /*click on the others li*/&nbsp; &nbsp; $("li[data-el='*']", parent).removeClass("selected");&nbsp;&nbsp; &nbsp; if ($this.hasClass("selected")) {&nbsp; &nbsp; &nbsp; &nbsp; /*click on li with selected class */&nbsp; &nbsp; &nbsp; $this.removeClass("selected");&nbsp; &nbsp; &nbsp; results[parentObj]=$.grep(results[parentObj], function(value) {&nbsp; &nbsp; &nbsp; &nbsp; return value != myClass; /* I used $.grep() to filter the contents of my object. This function remove a class that I previous added (remember that <li> was selected so this class is still in this obj) */&nbsp; &nbsp; &nbsp; });&nbsp; &nbsp; } else {&nbsp; &nbsp; &nbsp; $this.addClass("selected");&nbsp; &nbsp; &nbsp; results[parentObj].push(myClass) /* add a class on associative object */&nbsp; &nbsp; }&nbsp; }&nbsp;/* Here I use a EC6 technique to loop through my object => https://zellwk.com/blog/looping-through-js-objects/*/&nbsp; var entries = Object.entries(results);&nbsp; for (const [key, value] of entries) {&nbsp; &nbsp; if (value.length>0)&nbsp; &nbsp; &nbsp; &nbsp; /* add ONLY array with classes in it */&nbsp; &nbsp; &nbsp; control.push(value);&nbsp; &nbsp; else&nbsp; &nbsp; /* Here I know that if the array is empty all my child li have no selected class, so I can add "selected" class to the first li (i.e. <li> with data-el='*' as attribute)*/&nbsp; &nbsp; &nbsp; $(".nav[data-obj='"+key+"'] li[data-el='*']").addClass("selected");&nbsp; }&nbsp; /* Set all div in results to opacity:.5*/&nbsp; $(".results > div").css({"opacity":".5"});&nbsp; if(control.length>0){&nbsp; &nbsp; var c=allPossibleCases(control).toString(); /* use that function to find all combinations in control (that it is an array without empty associative objects. I transform it in string to use it as group classes to remove the opacity rule */&nbsp; &nbsp; $(c, container).removeAttr("style"); /* remove the opacity:.5 to all group class that I found in control array*/&nbsp; } else {&nbsp; &nbsp; $(".results > div").removeAttr("style"); /*if control is empty I set the initial state removing the opacity */&nbsp; }});function allPossibleCases(arr) {&nbsp; if (arr.length == 1) {&nbsp; &nbsp; return arr[0];&nbsp; } else {&nbsp; &nbsp; var result = [];&nbsp; &nbsp; var allCasesOfRest = allPossibleCases(arr.slice(1));&nbsp; &nbsp; for (var i = 0; i < allCasesOfRest.length; i++) {&nbsp; &nbsp; &nbsp; for (var j = 0; j < arr[0].length; j++) {&nbsp; &nbsp; &nbsp; &nbsp; result.push(arr[0][j] + allCasesOfRest[i]);&nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }&nbsp; &nbsp; return result;&nbsp; }}而已。工作中的所有代码:var results = {&nbsp; series:[],&nbsp; body:[],&nbsp; style:[]};var container=$(".results");$(".nav li").on('click', function(){&nbsp; var $this=$(this);&nbsp; var parent=$this.parent();&nbsp; var parentObj=$this.parent().data("obj");&nbsp; var myClass=$this.data("el");&nbsp; var control=[];&nbsp; if(myClass==="*") {&nbsp; &nbsp; if (!$this.hasClass("selected")) {&nbsp; &nbsp; &nbsp; $("li", parent).removeClass("selected");&nbsp; &nbsp; &nbsp; $this.addClass("selected");&nbsp; &nbsp; &nbsp; results[parentObj]=[];&nbsp; &nbsp; }&nbsp; } else {&nbsp; &nbsp; $("li[data-el='*']", parent).removeClass("selected");&nbsp; &nbsp; if ($this.hasClass("selected")) {&nbsp; &nbsp; &nbsp; $this.removeClass("selected");&nbsp; &nbsp; &nbsp; results[parentObj]=$.grep(results[parentObj], function(value) {&nbsp; &nbsp; &nbsp; &nbsp; return value != myClass;&nbsp; &nbsp; &nbsp; });&nbsp; &nbsp; } else {&nbsp; &nbsp; &nbsp; $this.addClass("selected");&nbsp; &nbsp; &nbsp; results[parentObj].push(myClass)&nbsp; &nbsp; }&nbsp; }&nbsp; var entries = Object.entries(results);&nbsp; for (const [key, value] of entries) {&nbsp; &nbsp; if (value.length>0)&nbsp; &nbsp; &nbsp; control.push(value);&nbsp; &nbsp; else&nbsp; &nbsp; &nbsp; $(".nav[data-obj='"+key+"'] li[data-el='*']").addClass("selected");&nbsp; }&nbsp; $(".results > div").css({"opacity":".5"});&nbsp; if(control.length>0){&nbsp; &nbsp; var c=allPossibleCases(control).toString();&nbsp; &nbsp; $(c, container).removeAttr("style");&nbsp; } else {&nbsp; &nbsp; $(".results > div").removeAttr("style");&nbsp; }});function allPossibleCases(arr) {&nbsp; if (arr.length == 1) {&nbsp; &nbsp; return arr[0];&nbsp; } else {&nbsp; &nbsp; var result = [];&nbsp; &nbsp; var allCasesOfRest = allPossibleCases(arr.slice(1));&nbsp; &nbsp; for (var i = 0; i < allCasesOfRest.length; i++) {&nbsp; &nbsp; &nbsp; for (var j = 0; j < arr[0].length; j++) {&nbsp; &nbsp; &nbsp; &nbsp; result.push(arr[0][j] + allCasesOfRest[i]);&nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }&nbsp; &nbsp; return result;&nbsp; }}ul {&nbsp; border-bottom: 1px solid black;&nbsp; padding-bottom: 10px;}li {&nbsp; display: inline-block;}.selected {&nbsp; background-color: red;}.results {&nbsp; display: flex;}.results > div {&nbsp; width: 100px;&nbsp; height: 100px;&nbsp; background: black;&nbsp; color: white;&nbsp; display: flex;&nbsp; justify-content: center;&nbsp; align-items: center;&nbsp; margin: 10px;}<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script><ul class="nav" data-obj="series">&nbsp; <li data-el="*" class="selected">All</li>&nbsp; <li data-el=".Series-1">Series 1</li>&nbsp; <li data-el=".Series-2">Series 2</li>&nbsp; <li data-el=".Series-3">Series 3</li></ul><ul class="nav" data-obj="body">&nbsp; <li data-el="*" class="selected">All</li>&nbsp; <li data-el=".Body-1">Body 1</li>&nbsp; <li data-el=".Body-2">Body 2</li>&nbsp; <li data-el=".Body-3">Body 3</li></ul><ul class="nav" data-obj="style">&nbsp; <li data-el="*" class="selected">All</li>&nbsp; <li data-el=".Style-1">Style 1</li>&nbsp; <li data-el=".Style-2">Style 2</li>&nbsp; <li data-el=".Style-3">Style 3</li></ul><div class="results">&nbsp; &nbsp;<div class="Series-1 Body-1 Style-1">Result 1</div>&nbsp; &nbsp;<div class="Series-1 Body-1 Style-1">Result 2</div>&nbsp; &nbsp;<div class="Series-2 Body-2 Style-2">Result 3</div>&nbsp; &nbsp;<div class="Series-2 Body-1 Style-2">Result 4</div>&nbsp; &nbsp;<div class="Series-3 Body-1 Style-1">Result 5</div>&nbsp; &nbsp;<div class="Series-3 Body-1 Style-1">Result 6</div>&nbsp; &nbsp;<div class="Series-3 Body-2 Style-2">Result 7</div>&nbsp; &nbsp;<div class="Series-2 Body-1 Style-3">Result 8</div></div>
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

JavaScript