【问题标题】:How to filter results in jQuery with multiple selects, including a date range?如何使用多个选择过滤 jQuery 中的结果,包括日期范围?
【发布时间】:2020-01-31 11:45:33
【问题描述】:

我正在尝试根据数据属性过滤结果。在大多数情况下,我认为我在那里(它适用于前 3 个选择器),但我在尝试将日期选择器纳入等式时遇到了麻烦。 在这一点上,我对我的方法的质疑是完全正确的——如果需要,我可以更改 HTML——所以请随时提供更好的解决方案。

为了方便任何愿意提供帮助的人,这里是小提琴:https://jsfiddle.net/rnbx0c3j/

谢谢你

选择器:

<div id="stats_filter">
    <div id="stats_filter_wrapper" class="grids">
        <div class="grid-3 select-wrapper server first">
            <label class="server">Server</label>
            <select id="select-server">
                <option value="all">All</option>
                <option value="NicNicFunGame">NicNicFunGame</option>
                <option value="GT3_races">GT3_races</option>
            </select>
        </div>
        <div class="grid-3 select-wrapper track">
            <label class="track">Track</label>
            <select id="select-track">
                <option value="all">All</option>
                <option value="ks_brands_hatch">ks_brands_hatch</option>
                <option value="Imola">Imola</option>
                <option value="Spa">Spa</option>
            </select>
        </div>
        <div class="grid-3 select-wrapper car">
            <label class="car">Car</label>
            <select id="select-car">
                <option value="all">All</option>
                <option value="ariel_atom_v8">ariel_atom_v8</option>
                <option value="rr_caterham_academy_620r">rr_caterham_academy_620r</option>
                <option value="ks_porsche_911_gt1">ks_porsche_911_gt1</option>
            </select>
        </div>
        <div class="grid-3 select-wrapper date">
            <label class="date">Date</label>
            <select id="select-date">
                <option value="all">All</option>
                <option value="7">Last 7 days</option>
                <option value="30">Last 30 days</option>
                <option value="182">Last 6 months</option>
                <option value="365">Last 12 months</option>
            </select>
        </div>
    </div>
</div>

要过滤的 HTML

<div class="stats-section" id="sectionID_1" data-server="NicNicFunGame" data-track="ks_brands_hatch" data-date="27/09/2019" data-car="ariel_atom_v8">sectionID_1</div>
<div class="stats-section" id="sectionID_2" data-server="NicNicFunGame" data-track="Imola" data-date="03/07/2019" data-car="rr_caterham_academy_620r">sectionID_2</div>
<div class="stats-section" id="sectionID_3" data-server="GT3_races" data-track="Spa" data-date="14/01/2019" data-car="ariel_atom_v8, ks_porsche_911_gt1">sectionID_3</div>

JS

var $select = $('#stats_filter select');
var $statsSection = $('.stats-section');

$select.change(function () {
    var include = '';
    var exclude = [];
    var showAll = true;
    var filterDate = false;

    $select.each(function () {
        var val = $(this).children(':selected').val();

        if (val !== 'all') {

            switch ($(this).prop('id')) {
                case 'select-server':
                    include += "[data-server='" + val + "']";
                    break;
                case 'select-track':
                    include += "[data-track='" + val + "']";
                    break;
                case 'select-car':
                    include += "[data-car*='" + val + "']";
                    break;
                case 'select-date':
                    var selectedDate = new Date(new Date().setDate(new Date().getDate() - val));
                    var dd = selectedDate.getDate();
                    var mm = selectedDate.getMonth() + 1;
                    var yyyy = selectedDate.getFullYear();
                    if (dd < 10) {
                        dd = '0' + dd;
                    }
                    if (mm < 10) {
                        mm = '0' + mm;
                    }
                    selectedDate = dd + '/' + mm + '/' + yyyy;

                    //exclude when date is out of range
                    $statsSection.each(function () {
                        var sectionDate = $(this).data('date');

                        if (process(sectionDate) < process(selectedDate)) {
                            exclude.push("[data-date='" + sectionDate + "']");
                        }
                        exclude.join(',');

                    });

                    function process(date) {
                        var parts = date.split("/");
                        return new Date(parts[2], parts[1] - 1, parts[0]);
                    }

                    filterDate = true;
                    break;
            }
            showAll = false;
        }

    });

    if (showAll) {
        $statsSection.show();
    } else {


        //HOW TO DEAL WITH THE DATES??
                if (filterDate == true) {
            alert('the following dates should be excluded from the results: ' + exclude);
        }

        //this works for the non-date selectors
        $statsSection.not($(include)).hide();
        $statsSection.filter($(include)).show();
    }
});

【问题讨论】:

  • 你为什么不使用alasql之类的东西
  • 我看到数据包含一个日期参数。为什么不将计算的过滤日期的 date.UTC() 与数据点的 date.UTC() 值进行比较? UTC 函数提供了自 1970 年以来的纯毫秒数,因此您的数据范围可以正常工作。如果你有一个大数据集要过滤,你可以为每个数据节点做一个 data-utc 参数作为加载过程,以避免以后重新计算。
  • @Vanquiished Wombat 感谢 UTC 提示,我肯定会调查一下。但是我的主要问题不是日期本身(可能我的问题不够清楚)。主要问题:我已经有一个具有正确数据属性的数组 [exclude] 可以从结果中排除(或包含),但我不明白如何从这里开始工作并根据日期选择器过滤正确的结果(见上面的小提琴>>选择日期)。谢谢!
  • @angel.bonev 我不希望再包含另一个库,因为它可以用普通的 JS / jQuery 完成(除非有很好的理由)
  • @NicoF 我明白了,但是用选择器搜索不是很快,管理起来会很困难

标签: jquery filter date-range


【解决方案1】:

因此,对于非日期项目,您的技术是计算应包含的元素的 jquery 选择器,然后将其应用于数据 div。

在构建“包含”变量时构建多个 jquery 过滤器是一个很好的方法。

对日期应用相同技术的困难在于,这会产生一个很难放入 jquery 选择器的范围测试。我的解决方案是构造一个符合条件的数据日期值数组,并在最后一步执行第二个过滤器。

变化是:

步骤 1. 定义一个新变量:

var dateInclude = [];

第 2 步。在确定日期是否有效的部分中,将有效值推送到 dataInclude 过滤器数组中

//exclude when date is out of range
$statsSection.each(function () {
    var sectionDate = $(this).data('date');

    if (process(sectionDate) > process(selectedDate)) {
        dateInclude.push("[data-date='" + sectionDate + "']");
    }

});

第 3 步:在输出部分,我们现在将 dateInclude 组合为第二个过滤器。请注意,您的初始过滤器作为布尔 AND 运行,但日期过滤器必须作为布尔 OR 运行。因此,在 show() 操作中应用 dateInclude 过滤器作为第二步。

$statsSection.hide();
include = (dateInclude.length > 0 && include === '' ? '*' : include);
dateInclude = (dateInclude.length === 0 ? ['*'] : dateInclude );
$('#info').html(include + ' :: ' + dateInclude.join());
$statsSection.filter(include).filter(dateInclude.join()).show();

第一行(下)抢先隐藏了所有的数据div。

$statsSection.hide();

接下来的几行(下面)对过滤器进行操作,以确保它们都有一个值。如果不存在日期过滤器,我们会注入一个全匹配,对于其他选择框的“包含”过滤器也是如此。

include = (dateInclude.length > 0 && include === '' ? '*' : include);
dateInclude = (dateInclude.length === 0 ? ['*'] : dateInclude );

最后我们把它放在一起如下。

$statsSection.filter(include).filter(dateInclude.join()).show();

为了帮助可视化它,我在小提琴中添加了一些输出

例如,选择 server=NicNicFunGame 和 date=last 六个月会生成过滤器:

$statsSection.filter("[data-server='NicNicFunGame']").filter("[data-date='27/09/2019'],[data-date='03/07/2019']").show();

https://jsfiddle.net/JamesE442/qktfbp15/38/查看我的工作小提琴

【讨论】:

  • 嗨,这太棒了,非常感谢。正如您在我对 angel.bonev 的评论中看到的那样,它也非常快!再次感谢队友
【解决方案2】:

您可以将所有stats-section 存储到对象数组中并使用array filter 进行搜索

var t0 = performance.now(); 
var initialized = false;
var $select = $('#stats_filter select'); 
function initialize() {
  mySelectors = [];
  $statsSection = $('.stats-section');
    console.log("First search will be costly");
    $($statsSection).each(function (i, e) {
        let temp = $(e).data();
        temp.element = $(e);
        let myDate = temp.date.split("/");
        temp.date = new Date(myDate[1] + "/" + myDate[0] + "/" + myDate[2]).getTime();//fix date format and convert to timestamp
        mySelectors.push(temp);
    });
    initialized = true;
}



$select.change(function () {
    var t0 = performance.now();
    if (!initialized)
        initialize();
    var result = mySelectors;
    $select.each(function () {
        var val = $(this).val(); //you don't need to search the selected child
        if (val !== 'all') {
            switch ($(this).prop('id')) {
                case 'select-server':
                    result = result.filter(obj => {
                        return obj.server === val;
                    });
                    break;
                case 'select-track':
                    result = result.filter(obj => {
                        return obj.track === val;
                    });
                    break;
                case 'select-car':
                    result = result.filter(obj => {
                        return obj.car === val;
                    });
                    break;
                case 'select-date':
                    var selectedDate = new Date(new Date().setDate(new Date().getDate() - val)).getTime(); // timestamp
                    result = result.filter(obj => {
                        return obj.date > selectedDate;
                    });
            }
        }

    });
    $($statsSection).hide();
    $.each(result, function (i, e) {
        $(e.element).show();
    });
    var t1 = performance.now();
    console.log("Search performance " + (t1 - t0) + " milliseconds.");
});
var t1 = performance.now();
console.log("Initialize performance " + (t1 - t0) + " milliseconds.");
.grids { clear: both;max-width: 1920px;margin: 0;}
#stats_filter_wrapper .select-wrapper { width: 25%; float:left; }
#stats_filter_wrapper .select-wrapper label { overflow: hidden; font-weight: 700; }
#stats_filter_wrapper .select-wrapper select { display: block; font-size: 16px; color: #6a6d73; line-height: 1.3; padding: 8px 25px 5px 8px; width: 100%; max-width: 100%; box-sizing: border-box; margin: 0; }
.stats-section{padding:20px 0;}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="stats_filter">
    <div id="stats_filter_wrapper" class="grids">
        <div class="grid-3 select-wrapper server first">
            <label class="server">Server</label>
            <select id="select-server">
                <option value="all">All</option>
                <option value="NicNicFunGame">NicNicFunGame</option>
                <option value="GT3_races">GT3_races</option>
            </select>
        </div>
        <div class="grid-3 select-wrapper track">
            <label class="track">Track</label>
            <select id="select-track">
                <option value="all">All</option>
                <option value="ks_brands_hatch">ks_brands_hatch</option>
                <option value="Imola">Imola</option>
                <option value="Spa">Spa</option>
            </select>
        </div>
        <div class="grid-3 select-wrapper car">
            <label class="car">Car</label>
            <select id="select-car">
                <option value="all">All</option>
                <option value="ariel_atom_v8">ariel_atom_v8</option>
                <option value="rr_caterham_academy_620r">rr_caterham_academy_620r</option>
                <option value="ks_porsche_911_gt1">ks_porsche_911_gt1</option>
            </select>
        </div>
        <div class="grid-3 select-wrapper date">
            <label class="date">Date</label>
            <select id="select-date">
                <option value="all">All</option>
                <option value="7">Last 7 days</option>
                <option value="30">Last 30 days</option>
                <option value="182">Last 6 months</option>
                <option value="365">Last 12 months</option>
            </select>
        </div>
    </div>
</div>
<div class="stats-section" id="sectionID_1" data-server="NicNicFunGame" data-track="ks_brands_hatch" data-date="27/09/2019" data-car="ariel_atom_v8">sectionID_1</div>
<div class="stats-section" id="sectionID_2" data-server="NicNicFunGame" data-track="Imola" data-date="03/07/2019" data-car="rr_caterham_academy_620r">sectionID_2</div>
<div class="stats-section" id="sectionID_3" data-server="GT3_races" data-track="Spa" data-date="14/01/2019" data-car="ariel_atom_v8, ks_porsche_911_gt1">sectionID_3</div>

【讨论】:

  • 嗨,伙计,非常感谢。我喜欢这种方法是多么干净(我正在把头撞在墙上,为什么我没有看到这个)!但是仅供参考,我在下面针对 Vanquided Wombat 测试了您的代码,即使仅在 3 个结果(0.344970703125ms 与 0.864990234375ms 的代码)上,我也发现性能存在显着差异。实际上,我最多可以获得 50 个结果,所以这是一个很大的因素。我想我必须去他的版本,但非常感谢你教我一些东西
  • 你的基准是什么?搜索还是初始化?
  • 如您所见,我正在将您的日期格式转换为他的代码初始化的时间戳,这是在搜索部分完成的。你可以得到你可以在第一次更改后初始化
  • 好的,很酷。仅供参考,时间戳正在初始化,页面上有 3 个部分(每个部分包含一堆表/数据)。不完全确定为什么这两种方法之间存在很大差异
  • 我已经更新了 sn-p 请现在检查它并对其进行基准测试,届时我会解释,但基准测试和搜索像我一样。你有我的支持,因为你是第一个关心性能的人。如果您使用选择器,则比较整数总是更快,您正在使用某种正则表达式或其他东西
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-02-26
  • 1970-01-01
  • 2012-09-12
  • 1970-01-01
  • 1970-01-01
  • 2018-10-18
  • 1970-01-01
相关资源
最近更新 更多