按数据属性数组过滤 jquery 个对象

Filtering jquery objects by data attribute array

是否有更简单、更好或更简洁的方法来过滤利用包含数组的数据属性的元素列表?

目前我们有一个很大的项目列表,每个项目都包含 1 个或多个标签,数组中存储在 "data-tags" 属性中,如下所示:

<div class="viewItem" data-tags='[{"id":1,"name":"Tag 01"},{"id":2,"name":"Tag 02"}]'></div>
<div class="viewItem" data-tags='[{"id":2,"name":"Tag 02"}]'></div>
<div class="viewItem" data-tags='[{"id":1,"name":"Tag 01"},{"id":3,"name":"Tag 03"}]'></div>

目的是仅显示数据标签数组中具有特定标签的 div。以下代码有效,但我觉得在处理大量项目时效率很低,想找到更好的答案,无论是使用 jquery 过滤器还是 grep 或其他。

$(function () {
    //Instantiate variables
    var $viewItems = $('.viewItem');
    var filterId = 2;

    //Hide all items in object array.
    $viewItems.hide(); 

    //Loop thru EACH item and show only those with matching id in array
    $viewItems.each(function () {
        var thisItem = $(this);
        var array = thisItem.data("tags");

        $.each(array, function (i, obj) {
            if (obj.id == filterId) { thisItem.show(); return false; }
        });                    
    });
});

您可以为每个标签创建 css classes。示例:tag-1、tag-2 等。 将标签放入 class 部分,如下所示:<div class="viewItem tag-1 tag2".../> 因此,您可以轻松 select/show/hide 任何标签组合,如下所示:

// Hide tag-1
$(".tag-1").css('display','none')
// Show tag-2
$(".tag-2").css('display','block');
// Select elements with tag-1 and tag-2
$(".tag-1 tag-2").css('background','pink');

使用jQuery grep 函数过滤您的元素。然后在 grep 函数中,解析 data-tags 属性并查找是否存在具有给定 id 的元素:

var filterId = 1;
var dataTags;
var arr = $.grep($('.viewItem'), function( el ) {
  dataTags = JSON.parse($(el).attr('data-tags'));
  return dataTags.find(el => el.id === filterId);
});
console.log(arr);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="viewItem" data-tags='[{"id":1,"name":"Tag 01"},{"id":2,"name":"Tag 02"}]'></div>
<div class="viewItem" data-tags='[{"id":2,"name":"Tag 023"}]'></div>
<div class="viewItem" data-tags='[{"id":1,"name":"Tag 01"},{"id":3,"name":"Tag 03"}]'></div>

首先,data 方法相当快:jQuery 仅在第一次访问时从 DOM 中读取值,但随后保留值(此中的对象case) 在内存中,并且不会再次读取 DOM 的数据属性。

因此,如果这些 JSON 值不是很大,按 id 过滤项目将不会是占用大部分时间的部分。最耗时的部分将是您调用 .hide().show() 的地方,因为它涉及与 DOM 和渲染的交互。

但是,如果你真的需要优化它,你可以通过这个 JSON id 值做一些预处理和键控你的元素,例如像这样:

$(function () {
    // Pre-processing: key all viewItems by the id in their data-tags:
    var hash = $('.viewItem').get().reduce(function (hash, div) {
        return $(div).data("tags").reduce(function (hash, o) {
            hash[o.id] = (hash[o.id] || []).concat(div);
            return hash;
        }, hash);
    }, {});

    // Actual filtering
    $('#apply').click(function() {
        var filterId = $('#filter').val();
        $('.viewItem').hide();
        $(hash[filterId]).show();
    });
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
Filter ID: <input id="filter"><button id="apply">Apply</button><br>

<div class="viewItem" data-tags='[{"id":1,"name":"Tag 01"},{"id":2,"name":"Tag 02"}]'>1,2</div>
<div class="viewItem" data-tags='[{"id":2,"name":"Tag 02"}]'>2</div>
<div class="viewItem" data-tags='[{"id":1,"name":"Tag 01"},{"id":3,"name":"Tag 03"}]'>1,3</div>

势在必行

由于创建散列的 函数式 方法可能看起来令人困惑,我在这里提供 强制性 替代方法。但是生成的散列对象将完全相同:

$(function () {
    // Pre-processing: key all viewItems by the id in their data-tags:
    var hash = [];
    $('.viewItem').each(function (i, div) {
        $.each($(div).data("tags"), function (j, obj) {
            if (!(obj.id in hash)) hash[obj.id] = [];
            hash[obj.id].push(div);
        });
    });

    // Actual filtering
    $('#apply').click(function() {
        var filterId = $('#filter').val();
        $('.viewItem').hide();
        $(hash[filterId]).show();
    });
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
Filter ID: <input id="filter"><button id="apply">Apply</button><br>

<div class="viewItem" data-tags='[{"id":1,"name":"Tag 01"},{"id":2,"name":"Tag 02"}]'>1,2</div>
<div class="viewItem" data-tags='[{"id":2,"name":"Tag 02"}]'>2</div>
<div class="viewItem" data-tags='[{"id":1,"name":"Tag 01"},{"id":3,"name":"Tag 03"}]'>1,3</div>

jQuery 过滤器怎么样?

var $viewItems = $('.viewItem');
var filterId = 2;

//Hide all items in object array.
$viewItems.hide(); 

//Loop thru EACH item and show only those with matching id in array
$viewItems.filter(function (i, el) {
  var dataTags = $(el).data("tags");
  return dataTags.filter(tag => tag.id === filterId).length
}).show()