3

对于所有 jQuery 英雄,我需要帮助!(再次)

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

我想用 jquery isotope 过滤一堆项目。我从插件主页改编了组合过滤器示例,效果很好,看起来像这样:

$(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 类:abc

类别 2:abc

类别 3:abc

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

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

提前致谢!

4

6 回答 6

13

将多种过滤器类型与 metafizzy 同位素过滤一起使用需要一个多维数组来保存每种过滤器类型的数组。

这里有一个活生生的例子

示例的 js 在这里

有关完整的代码解释,请参阅我对这个问题的回答

于 2013-12-10T09:49:45.980 回答
10

看看这里

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

DrewT 给出了相同的答案,但来自 Isotope 团队。

为了过滤你所要做的就是将每个组放在同一个对象下

var filters = {}; // should be outside the scope of the filtering function
 
//filtering function
$a.click(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;
 }
于 2015-05-25T22:30:35.023 回答
3

这是您可以遵循的 JS Fiddle 代码,用于带有多选下拉列表的同位素组合过滤器

$(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/

于 2018-04-10T08:31:41.870 回答
0

我可以让它工作,但它并不像我最初想象的那么简单。我认为您需要牢记以下几点:

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

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

这个关于限制性和非限制性 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+''});
            }
        });

});
于 2013-09-09T17:29:32.257 回答
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>
于 2021-02-10T11:27:42.713 回答
0

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

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

最重要的是,使用选择器并没有性能上的好处(如果选择器直接输入到一个querySelector或 jQuery 调用中,您可能会想到这一点)。Isotope 遍历每个项目并将选择器作为函数应用,无论:

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

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

于 2016-11-01T13:34:54.507 回答