You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Isotope自定义函数无法访问游戏卡片HTML属性的技术求助

问题

开发桌游俱乐部管理网站的游戏展示页面,使用Isotope实现筛选功能,游戏类型、语言筛选正常,但按最小/最大玩家数筛选时,自定义筛选函数无法获取游戏卡片的data-minplayers、data-maxplayers属性值,输出undefined。

技术栈:Laravel 10.8、Bootstrap 5.3、jQuery 3.7.0、Isotope-layout 3.0.6、Masonry-layout 4.2.2

相关代码

JS代码

$(window).on('load', function(){

    var filtersFunctions = {
        minplayers: function(){
            var itemValue = $(this).attr('data-minplayers');
            var filterValue = $('.isotope-filter-minplayers.active').attr('data-players');

            return parseInt(itemValue, 10) >= parseInt(filterValue, 10);
        },
        maxplayers: function(){
            var itemValue = $(this).attr('data-maxplayers');
            var filterValue = $('.isotope-filter-maxplayers.active').attr('data-players');

            return parseInt(itemValue, 10) <= parseInt(filterValue, 10);
        }
    };

    var filters = {};

    var $grid = $('.isotope-grid').isotope({
        itemSelector: '.isotope-card',
        layoutMode: 'masonry'
    });

    $('#isotope-filters').on('click', '.isotope-filter', function(){

        var $this = $(this);
        var $buttonGroup = $this.parents('.isotope-group');
        var filterGroup = $buttonGroup.attr('data-filter-group');

        if($this.hasClass('active')){
            delete filters[filterGroup];
            $this.removeClass('active');
        }
        else{
            $buttonGroup.find('.isotope-filter').removeClass('active');
            $this.addClass('active');
            filters[filterGroup] = $this.attr('data-filter');
        }

        var filterValue = filtersFunctions[filters[filterGroup]] || concatValues(filters);

        $grid.isotope({filter: filterValue});
    });
});

function concatValues(obj){

    var value = '';

    for(var prop in obj){
        value += obj[prop];
    }

    return value;
}

筛选按钮HTML代码

<div id="isotope-filters">
    <div class="card-group shadow">
        <div class="card">
            <div class="card-body isotope-group" data-filter-group="types">
                <h5 class="card-title">Types de jeux</h5>
                <button type="button" class="btn btn-outline-primary btn-sm isotope-filter" data-filter=".type-null">
                    Jeux sans types
                </button>
                <button type="button" class="btn btn-outline-primary btn-sm isotope-filter" data-filter=".type-1">
                    Type 1
                </button>
                <button type="button" class="btn btn-outline-primary btn-sm isotope-filter" data-filter=".type-2">
                    Type 2
                </button>
                <button type="button" class="btn btn-outline-primary btn-sm isotope-filter" data-filter=".type-3">
                    Type 3
                </button>
            </div>
        </div>
        <div class="card">
            <div class="card-body isotope-group" data-filter-group="langs">
                <h5 class="card-title">Langues</h5>
                <button type="button" class="btn btn-outline-info btn-sm isotope-filter" data-filter=".lang-fr">
                    FR
                </button>
                <button type="button" class="btn btn-outline-info btn-sm isotope-filter" data-filter=".lang-en">
                    EN
                </button>
                <button type="button" class="btn btn-outline-info btn-sm isotope-filter" data-filter=".lang-pt">
                    PT
                </button>
            </div>
        </div>
        <div class="card">
            <div class="card-body isotope-group" data-filter-group="minplayers">
                <h5 class="card-title">Joueurs min.</h5>
                <button type="button" class="btn btn-outline-warning btn-sm isotope-filter isotope-filter-minplayers" data-filter="minplayers" data-players="1">
                    1
                </button>
                <button type="button" class="btn btn-outline-warning btn-sm isotope-filter isotope-filter-minplayers" data-filter="minplayers" data-players="2">
                    2
                </button>
                <button type="button" class="btn btn-outline-warning btn-sm isotope-filter isotope-filter-minplayers" data-filter="minplayers" data-players="3">
                    3
                </button>
            </div>
        </div>
        <div class="card">
            <div class="card-body isotope-group" data-filter-group="maxplayers">
                <h5 class="card-title">Joueurs max.</h5>
                <button type="button" class="btn btn-outline-danger btn-sm isotope-filter isotope-filter-maxplayers" data-filter="maxplayers" data-players="4">
                    4
                </button>
                <button type="button" class="btn btn-outline-danger btn-sm isotope-filter isotope-filter-maxplayers" data-filter="maxplayers" data-players="5">
                    5
                </button>
                <button type="button" class="btn btn-outline-danger btn-sm isotope-filter isotope-filter-maxplayers" data-filter="maxplayers" data-players="6">
                    6
                </button>
            </div>
        </div>
    </div>
</div>

游戏卡片HTML代码

<div class="row isotope-grid">
    <div class="isotope-card lang-fr type-1" data-minplayers="2" data-maxplayers="5">
        <div class="card h-100 mb-3 shadow">
            <img src="https://picsum.photos/500" class="card-img rounded-bottom-0 object-fit-cover" alt="Adélaïde Allain-Hoarau">
            <div class="card-body">
                <h5 class="card-title">GAME TITLE</h5>
                <p class="card-text">GAME DESC</p>
                <div class="card-text mb-2">
                    <div class="btn-group btn-group-sm">
                        <a href="http://lbl.test/games/1" class="btn btn-success">Détails</a>
                        <a href="http://lbl.test/games/1" target="_blank" class="btn btn-success">
                            <i class="fa-solid fa-arrow-up-right-from-square"></i>
                        </a>
                    </div>
                </div>
            </div>
            <div class="card-footer">
                <small class="text-body-secondary">Ajouté le 06/06/2023 à 10:31</small><br>
                <small class="text-body-secondary">Modifié le 06/06/2023 à 10:31</small>
            </div>
        </div>
    </div>
    <div class="isotope-card lang-en type-2" data-minplayers="3" data-maxplayers="4">
        <div class="card h-100 mb-3 shadow">
            <img src="https://picsum.photos/500" class="card-img rounded-bottom-0 object-fit-cover" alt="Adélaïde Allain-Hoarau">
            <div class="card-body">
                <h5 class="card-title">GAME TITLE</h5>
                <p class="card-text">GAME DESC</p>
                <div class="card-text mb-2">
                    <div class="btn-group btn-group-sm">
                        <a href="http://lbl.test/games/1" class="btn btn-success">Détails</a>
                        <a href="http://lbl.test/games/1" target="_blank" class="btn btn-success">
                            <i class="fa-solid fa-arrow-up-right-from-square"></i>
                        </a>
                    </div>
                </div>
            </div>
            <div class="card-footer">
                <small class="text-body-secondary">Ajouté le 06/06/2023 à 10:31</small><br>
                <small class="text-body-secondary">Modifié le 06/06/2023 à 10:31</small>
            </div>
        </div>
    </div>
</div>
解决方案

问题根源是自定义筛选函数中this指向异常,且多条件筛选逻辑无法同时兼容类选择器和自定义函数。修改后的代码如下:

$(window).on('load', function(){
    var filtersFunctions = {
        minplayers: function(element){
            var $item = $(element);
            var filterValue = $('.isotope-filter-minplayers.active').attr('data-players');
            if(!filterValue) return true;
            var itemValue = $item.data('minplayers');
            return parseInt(itemValue, 10) >= parseInt(filterValue, 10);
        },
        maxplayers: function(element){
            var $item = $(element);
            var filterValue = $('.isotope-filter-maxplayers.active').attr('data-players');
            if(!filterValue) return true;
            var itemValue = $item.data('maxplayers');
            return parseInt(itemValue, 10) <= parseInt(filterValue, 10);
        }
    };

    var filters = {};

    var $grid = $('.isotope-grid').isotope({
        itemSelector: '.isotope-card',
        layoutMode: 'masonry'
    });

    $('#isotope-filters').on('click', '.isotope-filter', function(){
        var $this = $(this);
        var $buttonGroup = $this.parents('.isotope-group');
        var filterGroup = $buttonGroup.attr('data-filter-group');

        if($this.hasClass('active')){
            delete filters[filterGroup];
            $this.removeClass('active');
        } else {
            $buttonGroup.find('.isotope-filter').removeClass('active');
            $this.addClass('active');
            filters[filterGroup] = $this.attr('data-filter');
        }

        var filterValue = function(element){
            var $element = $(element);
            var passes = true;
            for(var group in filters){
                var filter = filters[group];
                if(filtersFunctions[filter]){
                    passes = passes && filtersFunctions[filter](element);
                } else {
                    passes = passes && $element.is(filter);
                }
            }
            return passes;
        };

        $grid.isotope({filter: filterValue});
    });
});

修改要点

  1. 修复元素指向:自定义筛选函数改为接收element参数,直接操作游戏卡片DOM元素,避免this指向错误。
  2. 优化属性获取:用jQuery的data()方法替代attr(),更稳定读取data-*属性。
  3. 完善多条件筛选:替换原有的concatValues函数,改为遍历所有筛选组,同时支持类选择器和自定义函数筛选,实现多条件叠加生效。
  4. 空值兼容处理:当没有激活的玩家数筛选按钮时,默认返回true,不干扰其他筛选条件。

内容的提问来源于stack exchange,提问作者SatanicGeek

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 09:37:07