为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

慕田峪7331174 2022-01-13 16:30:10
我有 3 个单独的菜单。如果从该特定菜单中未选择任何内容,则它们都默认为“全部”。菜单项是过滤器,您可以从每个菜单中选择任意数量的过滤器。当点击过滤器时,这将构建 3 个包含所选项目的数组(请参见下文)。每个菜单中的过滤器都链接或包含到其他菜单,因此结果必须满足所有选定的过滤器,否则它会被禁用类。我已经成功编写了 JS 来处理每个菜单的行为,因此使用 css 类突出显示选定的菜单项/过滤器。所以这一切都很好。我遇到的问题是当我尝试过滤结果时。当它们被单击时,它们会填充来自菜单过滤器的值,如果单击过滤器两次,则该项目将从数组中删除。随着这些数组的变化,我正在调用一个函数来更新结果。所以上面的更新函数只有在所有数组都有项目时才有效。所以我开始向上述条件添加进一步的逻辑,开始检查每个数组是否有项目,如果他们没有忽略它们,只是根据其他的过滤。显然,这会导致有进一步的逻辑来检查 3 个数组中的 2 个是否为空,等等。我觉得必须有更好的方法来做到这一点,而无需数十个嵌套的 if else 语句。也许我需要从完全不同的方式接近。非常感谢任何帮助。谢谢。
查看完整描述

1 回答

?
牧羊人nacy

TA贡献1862条经验 获得超7个赞

在我添加我的解决方案之前,我必须感谢@ffriend和他的函数来找出两个或多个数组中的所有组合(为此给他+1 ;)):Finding All Combinations (Cartesian product) of JavaScript array values


这个功能非常有用,我在我的解决方案中使用了。


这是针对您的问题的不同方法,因此我当然必须更改您的 HTML 和 jQuery。


首先是HTML。为了创建与您相同的过滤器系统,我决定只使用没有任何特定属性的类:


<div class="results">

   <div class="Series-1 Body-1 Style-1">Result 1</div>

   <div class="Series-1 Body-1 Style-1">Result 2</div>

   <div class="Series-2 Body-2 Style-2">Result 3</div>

   <div class="Series-2 Body-1 Style-2">Result 4</div>

   <div class="Series-3 Body-1 Style-1">Result 5</div>

   <div class="Series-3 Body-1 Style-1">Result 6</div>

   <div class="Series-3 Body-2 Style-2">Result 7</div>

   <div class="Series-2 Body-1 Style-3">Result 8</div>

</div>

...我创建了与所有导航列表的关系(也使用dot)


<ul class="nav" data-obj="series">

  <li data-el="*" class="selected">All</li>

  <li data-el=".Series-1">Series 1</li>

  <li data-el=".Series-2">Series 2</li>

  <li data-el=".Series-3">Series 3</li>

</ul>


<ul class="nav" data-obj="body">

  <li data-el="*" class="selected">All</li>

  <li data-el=".Body-1">Body 1</li>

  <li data-el=".Body-2">Body 2</li>

  <li data-el=".Body-3">Body 3</li>

</ul>


<ul class="nav" data-obj="style">

  <li data-el="*" class="selected">All</li>

  <li data-el=".Style-1">Style 1</li>

  <li data-el=".Style-2">Style 2</li>

  <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 = {

  series:[],

  body:[],

  style:[]

};


/* put the results containet in a variable */

var container=$(".results");


$(".nav li").on('click', function(){

  /*this is the general function that works for all your clicks */  


  /*set a few of variables */

  var $this=$(this);

  var parent=$this.parent();

  var parentObj=$this.parent().data("obj");

  var myClass=$this.data("el");

  var control=[]; /*this is an empty array that will set with your different classes*/


  if(myClass==="*") {

    /*click on first li*/

    if (!$this.hasClass("selected")) {

        /*do something if it didin't have the selected class*/

      $("li", parent).removeClass("selected"); /*remove selected classes from all li in my parent ul*/

      $this.addClass("selected");

      results[parentObj]=[];/* empty my associative object: series, body or style */

    }

  } else {

    /*click on the others li*/

    $("li[data-el='*']", parent).removeClass("selected"); 


    if ($this.hasClass("selected")) {

        /*click on li with selected class */

      $this.removeClass("selected");


      results[parentObj]=$.grep(results[parentObj], function(value) {

        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) */

      });

    } else {

      $this.addClass("selected");

      results[parentObj].push(myClass) /* add a class on associative object */

    }

  }

 /* Here I use a EC6 technique to loop through my object => https://zellwk.com/blog/looping-through-js-objects/*/

  var entries = Object.entries(results);


  for (const [key, value] of entries) {

    if (value.length>0)

        /* add ONLY array with classes in it */

      control.push(value);

    else

    /* 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)*/

      $(".nav[data-obj='"+key+"'] li[data-el='*']").addClass("selected");

  }



  /* Set all div in results to opacity:.5*/

  $(".results > div").css({"opacity":".5"});


  if(control.length>0){

    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 */

    $(c, container).removeAttr("style"); /* remove the opacity:.5 to all group class that I found in control array*/

  } else {

    $(".results > div").removeAttr("style"); /*if control is empty I set the initial state removing the opacity */

  }

});


function allPossibleCases(arr) {

  if (arr.length == 1) {

    return arr[0];

  } else {

    var result = [];

    var allCasesOfRest = allPossibleCases(arr.slice(1));

    for (var i = 0; i < allCasesOfRest.length; i++) {

      for (var j = 0; j < arr[0].length; j++) {

        result.push(arr[0][j] + allCasesOfRest[i]);

      }

    }

    return result;

  }

}

而已。工作中的所有代码:

var results = {

  series:[],

  body:[],

  style:[]

};


var container=$(".results");


$(".nav li").on('click', function(){

  var $this=$(this);

  var parent=$this.parent();

  var parentObj=$this.parent().data("obj");

  var myClass=$this.data("el");

  var control=[];


  if(myClass==="*") {

    if (!$this.hasClass("selected")) {

      $("li", parent).removeClass("selected");

      $this.addClass("selected");

      results[parentObj]=[];

    }

  } else {

    $("li[data-el='*']", parent).removeClass("selected");


    if ($this.hasClass("selected")) {

      $this.removeClass("selected");


      results[parentObj]=$.grep(results[parentObj], function(value) {

        return value != myClass;

      });

    } else {

      $this.addClass("selected");

      results[parentObj].push(myClass)

    }

  }


  var entries = Object.entries(results);


  for (const [key, value] of entries) {

    if (value.length>0)

      control.push(value);

    else

      $(".nav[data-obj='"+key+"'] li[data-el='*']").addClass("selected");

  }


  $(".results > div").css({"opacity":".5"});


  if(control.length>0){

    var c=allPossibleCases(control).toString();

    $(c, container).removeAttr("style");

  } else {

    $(".results > div").removeAttr("style");

  }

});


function allPossibleCases(arr) {

  if (arr.length == 1) {

    return arr[0];

  } else {

    var result = [];

    var allCasesOfRest = allPossibleCases(arr.slice(1));

    for (var i = 0; i < allCasesOfRest.length; i++) {

      for (var j = 0; j < arr[0].length; j++) {

        result.push(arr[0][j] + allCasesOfRest[i]);

      }

    }

    return result;

  }

}

ul {

  border-bottom: 1px solid black;

  padding-bottom: 10px;

}


li {

  display: inline-block;

}


.selected {

  background-color: red;

}


.results {

  display: flex;

}


.results > div {

  width: 100px;

  height: 100px;

  background: black;

  color: white;

  display: flex;

  justify-content: center;

  align-items: center;

  margin: 10px;

}

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>


<ul class="nav" data-obj="series">

  <li data-el="*" class="selected">All</li>

  <li data-el=".Series-1">Series 1</li>

  <li data-el=".Series-2">Series 2</li>

  <li data-el=".Series-3">Series 3</li>

</ul>


<ul class="nav" data-obj="body">

  <li data-el="*" class="selected">All</li>

  <li data-el=".Body-1">Body 1</li>

  <li data-el=".Body-2">Body 2</li>

  <li data-el=".Body-3">Body 3</li>

</ul>


<ul class="nav" data-obj="style">

  <li data-el="*" class="selected">All</li>

  <li data-el=".Style-1">Style 1</li>

  <li data-el=".Style-2">Style 2</li>

  <li data-el=".Style-3">Style 3</li>

</ul>


<div class="results">

   <div class="Series-1 Body-1 Style-1">Result 1</div>

   <div class="Series-1 Body-1 Style-1">Result 2</div>

   <div class="Series-2 Body-2 Style-2">Result 3</div>

   <div class="Series-2 Body-1 Style-2">Result 4</div>

   <div class="Series-3 Body-1 Style-1">Result 5</div>

   <div class="Series-3 Body-1 Style-1">Result 6</div>

   <div class="Series-3 Body-2 Style-2">Result 7</div>

   <div class="Series-2 Body-1 Style-3">Result 8</div>

</div>


查看完整回答
反对 回复 2022-01-13
  • 1 回答
  • 0 关注
  • 193 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号