同位素:组合过滤+多重选择

时间:2013-07-09 16:09:10

标签: jquery jquery-isotope

对于那里的所有jQuery heros,我需要帮助! (再次)

我在互联网上发现了类似的问题,但到目前为止还没有答案: - /

我想用jquery同位素过滤一堆物品。我从插件主页调整了组合过滤器示例,它工作正常,看起来像这样:

$(function () {
var $container = $('#container'),
    filters = {};
$container.isotope({
    itemSelector: '.item',
    filter: '',
});

// filter links
$('.filter a').click(function () {
    var $this = $(this);
    // don't proceed if already selected
    if ($this.hasClass('selected')) {
        return;
    }

    var $optionSet = $this.parents('.option-set');
    // change selected class
    $optionSet.find('.selected').removeClass('selected');
    $this.addClass('selected');

    // store filter value in object
    // i.e. filters.color = 'red'
    var group = $optionSet.attr('data-filter-group');
    filters[group] = $this.attr('data-filter-value');

    // convert object into array
    var isoFilters = [];
    for (var prop in filters) {
        isoFilters.push(filters[prop])
    }
    var selector = isoFilters.join('');
    $container.isotope({
        filter: selector
    });
    return false;
}); });

和过滤器菜单的一些html:

<div id="nav">
    <ul class="filter option-set" data-filter-group="who">
        <li><a href="#filter-who-any" data-filter-value="" class="selected">Any</a></li>
        <li><a href="#filter-who-boys" data-filter-value=".boys">Boys</a></li>
        <li><a href="#filter-who-girls" data-filter-value=".girls">Girls</a></li>
    </ul>

</div>

我设置了一个包含3个过滤器类别的小提琴演示,可以合并: jsFiddle

现在,我想从每个类别中选择多个标记:

第1类: OR b OR c

分类2: OR b OR c

分类3: OR b OR c

desandro有一个check-box-example,但这不是我正在寻找的东西,因为我想在类别之间保持AND条件。基本上我想要3个过滤器类别,每个过滤器类别都有一些复选框(或链接,但我想复选框更实用)。 我认为两个示例中使用的方法完全不同,我不知道如何组合它们的功能。

我希望你明白我的观点,任何人都可以帮我找到解决方案。

提前致谢!

6 个答案:

答案 0 :(得分:13)

使用具有metafizzy同位素过滤的多种过滤器类型需要多维数组来保存每种过滤器类型的数组。

我有一个实例here

示例中的js为here

有关完整的代码说明,请参阅我对this question

的回答

答案 1 :(得分:5)

看看这里

http://codepen.io/desandro/pen/btFfG

DrewT的答案与Isotope团队的答案相同。

为了过滤,您只需要将每个组放在同一个对象下

        var filters = {};//sould be outside the scope of the filtering function


  $a.click(function(){//filtering function
                var group = $optionSet.attr('data-filter-group');
             var filterGroup = filters[group];
                              if (!filterGroup) {
                                  filterGroup = filters[group] = [];
                              }
         filters[ group ].push($this.attr('data-filter-value'));
  })

现在您要做的就是调用getComboFilter函数(您不必理解getComboFilter中的代码,将其视为同位素的一部分)

     var comboFilter = getComboFilter( filters );
 $container.isotope({ filter: comboFilter});

function getComboFilter( filters ) {
  var i = 0;
  var comboFilters = [];
  var message = [];

  for ( var prop in filters ) {
    message.push( filters[ prop ].join(' ') );
    var filterGroup = filters[ prop ];
    // skip to next filter group if it doesn't have any values
    if ( !filterGroup.length ) {
      continue;
    }
    if ( i === 0 ) {
      // copy to new array
      comboFilters = filterGroup.slice(0);
    } else {
      var filterSelectors = [];
      // copy to fresh array
      var groupCombo = comboFilters.slice(0); // [ A, B ]
      // merge filter Groups
      for (var k=0, len3 = filterGroup.length; k < len3; k++) {
        for (var j=0, len2 = groupCombo.length; j < len2; j++) {
          filterSelectors.push( groupCombo[j] + filterGroup[k] ); // [ 1, 2 ]
        }

      }
      // apply filter selectors to combo filters for next group
      comboFilters = filterSelectors;
    }
    i++;
  }

  var comboFilter = comboFilters.join(', ');
  return comboFilter;
}

答案 2 :(得分:3)

以下是同位素组合过滤器可以使用多个选择下拉列表的JS小提琴代码

$(document).ready(function(){
  // init Isotope
  var $grid = $('.grid').isotope({
    itemSelector: '.item'
  });

  // store filter for each group
  var filters = {};

  $('.filters').on('change', '.filters-select', function(){
    var $this = $(this);
    var filterGroup = $this.attr('data-filter-group');
    filters[ filterGroup ] = $this.val();
    var filterValue = concatValues( filters );
    $grid.isotope({ filter: filterValue });
  });

  // flatten object by concatting values
  function concatValues( obj ) {
    var value = '';
    for ( var prop in obj ) {
      value += obj[ prop ];
    }
    return value;
  }
});

https://jsfiddle.net/srikanthLavudia/vhrbqn6p/

答案 3 :(得分:0)

我可以让它发挥作用,但它并不像我想象的那样直截了当。 我想你需要记住几件事:

  1. 如果您想使用限制性条件,那么我建议您不要使用“data-filter-value”选项。相反,将过滤器变量作为类。然后,您需要在onclick事件中自己激发同位素功能。 这是因为否则当用户点击按钮时您将触发“默认”同位素功能,并且您将无法实现限制性AND提及。

  2. 在同一方向,您需要为要使用的嵌套过滤器选项的每个组合使用新变量名(所以新类)。否则,我没有看到其他方式(目前)获得限制性条件。

  3. 关于限制性和非限制性AND子句的这个概念就像外部和内部连接之间的区别。如果你想处理两个过滤器,一个是另一个过滤器的子过滤器,那么你应该使用这个概念。
    一个例子就是可以按品牌过滤的电子书列表,另一个基于它们所属的不同价格范围的子过滤器。

    我在下面给出了一个代码示例,我实现了这个想法,它可以给你一个我的意思的暗示:

    HTML:

    <!--Filters section -->
    <div id="filters">
        <ul id="optionSet1" class="option-set" data-option-key="filter">
               <li><a id="filter10" href="#filter" class="selected">Everything</a></li>
            <c:forEach var="brand" items="${brands}" varStatus="status" >
                 <li><a id="filter1${status.count}" href="#filter" class='${brand}'>${brand}</a></li>
            </c:forEach>
        </ul>
        <ul id="optionSet2" class="option-set" data-option-key="filter">
            <li><a id="filter20" href="#filter" class="selected">Any Price</a>  </li>
        <c:forEach var="brandPrice" items="${brandPrices}" varStatus="status" >
            <li><a id="filter2${status.count}" href="#filter" class='${brandPrice}'>${brandPrice}</a></li>
        </c:forEach>
        </ul>
    </div>  
    
    
    <!--Elements to filter -->
    <div id="portfolio-wrapper" class="row">
        <c:forEach var="publication" items="${publications}" varStatus="status" >               
            <div class='span4 portfolio-item ${publication.filterOption1} ${publication.filterOption2} ${publication.filterOption3}...'>
    <!-- filterOption3 would be the combination of filterOption1 and filterOption2, you can make this building a string as the addition of filterOption1 and filterOption2 strings-->
                <!--Content to display-->           
        </c:forEach>
    </div>
    

    的javascript:

    $(function(){
    
            $("a[id^='filter1']").on('click', function() {
    //          alert($(this).attr('class'));
    //          alert($('#optionSet2 .selected').attr('class'));
                var myclass = $('#optionSet2 .selected').attr('class');
                myclass = myclass.replace(' selected','');
                myclass = myclass.replace('selected','');
                var myclass2 = $(this).attr('class');
                myclass2 = myclass2.replace(' selected','');
                myclass2 = myclass2.replace('selected','');
                if($(myclass=='' && myclass2==''){
                    $('#portfolio-wrapper').isotope({ filter: '*'});
                }else if(myclass==''){
                    $('#portfolio-wrapper').isotope({ filter: '.'+ myclass2+'' });
                }else if(myclass2==''){
                    $('#portfolio-wrapper').isotope({ filter: '.'+myclass+'' });
                }else{
    
                    $('#portfolio-wrapper').isotope({ filter: '.'+myclass2+myclass+''});
                }   
            });
    
            $("a[id^='filter2']").on('click', function() {
    //          alert($(this).attr('class'));
    //          alert($('#optionSet1 .selected').attr('class'));
                var myclass = $('#optionSet1 .selected').attr('class');
                myclass = myclass.replace(' selected','');
                myclass = myclass.replace('selected','');
                var myclass2 = $(this).attr('class');
                myclass2 = myclass2.replace(' selected','');
                myclass2 = myclass2.replace('selected','');
                if(myclass=='' && myclass2==''){
                    $('#portfolio-wrapper').isotope({ filter: '*'});
                }else if(myclass==''){
                    $('#portfolio-wrapper').isotope({ filter: '.'+ myclass2+'' });
                }else if(myclass2==''){
                    $('#portfolio-wrapper').isotope({ filter: '.'+myclass+'' });
                }else{
    
                    $('#portfolio-wrapper').isotope({ filter: '.'+myclass+myclass2+''});
                }
            });
    
    });
    

答案 4 :(得分:0)

很抱歉疏通这个问题,但我最近遇到了同样的问题而且(imho)浪费了很多时间用组合选择器来解决这个问题。 (将数组A中的每个类与数组B中的每个类组合起来等)。

使用过滤功能。它允许任意复杂性,并且可能是所有非平凡案例的正确选择。

最重要的是,使用选择器没有性能优势(如果将选择器直接送入querySelector或jQuery调用,您可能会期望这样做)。 Isotope遍历每个项目并将选择器应用为函数,无论如何:

return function( item ) {
  return matchesSelector( item.element, filter );
};

因此,您可以将过滤逻辑放入函数中,而不是尝试生成选择器字符串。

答案 5 :(得分:0)

不喜欢jQuery?我修改了 http://codepen.io/desandro/pen/btFfG 中的代码,@Luke 作为对 ESNext/Vanilla 的回答发布了该代码。

我想我会发布这个,因为这是一个相当不错的问题。

这里唯一的区别是,您必须自己创建 HTML。

class Metafizzy {
constructor(isotope) {
    this.isotope = isotope; // pass Isotope
    this.filters = {};
}

run(optionsContainerID, filterDisplayID) {
    let options = document.getElementById(optionsContainerID);
    let filterDisplay = document.getElementById(filterDisplayID);
    
    // do stuff when checkbox change
    options.addEventListener('change', (event) => {
        let inputElem = event.target;
        this.manageInputElement(inputElem);
        
        let comboFilter = this.getComboFilter(this.filters);
        
        this.isotope.arrange({ filter: comboFilter });
        
        //console.log(comboFilter); // uncomment to see the current filter output
    });
}

manageInputElement(inputElem) {
    let _this = this;
    // get the closest matching parent, and it's attribute value
    let parent = inputElem.closest('.iso-option-set');
    let group = parent.getAttribute('data-group');
    // create array for filter group, if not there yet
    let filterGroup = this.filters[group];
    if ( ! filterGroup) {
        filterGroup = this.filters[group] = [];
    }
    
    let isAll = inputElem.classList.contains('iso-all');
    // reset filter group if the all box was checked
    
    if (inputElem.type === 'checkbox') {
        this.doCheckBoxStuff(inputElem, parent, group, filterGroup, isAll)
    } else if (inputElem.type === 'range') {
        console.log('is element type "range"')
    }
    
}

doCheckBoxStuff(checkbox, parent, group, filterGroup, isAll) {
    if (isAll) {
        delete this.filters[group];
        if ( ! checkbox.checked) {
            checkbox.checked = true;
        }
    }
    // index of
    let hasCheckboxValue = filterGroup.includes(checkbox.value);
    let index = hasCheckboxValue ? 1 : -1;
    
    if (checkbox.checked) {
        let selector = isAll ? 'input' : 'input.iso-all';
        let allButton = parent.querySelector(selector);
        if (allButton) {
            allButton.checked = false;
        }
        
        if ( ! isAll && hasCheckboxValue === false) {
            // add filter to group
            this.filters[group].push(checkbox.value);
        }
        
    } else if ( ! isAll) {
        // remove filter from group
        // gets the index of the property by value
        function findWithAttr(array, value) {
            for(let i = 0; i < array.length; i += 1) {
                if(array[i] === value) {
                    return i;
                }
            }
            return -1;
        }
        let startIndex = findWithAttr(this.filters[ group ], checkbox.value)
        
        this.filters[ group ].splice( startIndex, 1 );
        // if all boxes unchecked, check the iso-all
        if ( ! parent.querySelectorAll('input:not(.iso-all):checked').length) {
            parent.querySelector('input.iso-all').checked = true;
        }
    }
}

getComboFilter(filters) {
    let i = 0;
    let comboFilters = [];
    let message = [];
    
    for (let prop in filters) {
        message.push(filters[prop].join(' '));
        let filterGroup = filters[prop];
        // skip to next filter group if it doesn't have any values
        if ( ! filterGroup.length) {
            continue;
        }
        if (i === 0) {
            // copy to new array
            comboFilters = filterGroup.slice(0);
        } else {
            let filterSelectors = [];
            // copy to fresh array
            let groupCombo = comboFilters.slice(0); // [ A, B ]
            // merge filter Groups
            for (let k = 0, len3 = filterGroup.length; k < len3; k++) {
                for (let j = 0, len2 = groupCombo.length; j < len2; j++) {
                    filterSelectors.push(groupCombo[j] + filterGroup[k]); // [ 1, 2 ]
                }
                
            }
            // apply filter selectors to combo filters for next group
            comboFilters = filterSelectors;
        }
        i++;
    }
    
    let comboFilter = comboFilters.join(', ');
    return comboFilter;
 }
}

这是实例化它的方式:

 <script>
    window.onload = function () {
        let element = document.getElementById('iso-filter-display');
        let iso = new Isotope(element, {
            // options
            itemSelector: '.iso-display-element'
        });
        let isoFilter = new Metafizzy(iso);
        isoFilter.run('iso-options-container','iso-filter-display')
    };
  </script>