jquery 数据选择器

Posted

技术标签:

【中文标题】jquery 数据选择器【英文标题】:jquery data selector 【发布时间】:2011-02-22 21:40:13 【问题描述】:

我需要根据存储在元素的.data() 对象中的值来选择元素。至少,我想使用选择器选择***数据属性,可能是这样的:

$('a').data("category","music");
$('a:data(category=music)');

或者选择器可能是常规属性选择器格式:

$('a[category=music]');

或属性格式,但带有说明符以表明它在.data()中:

$('a[:category=music]');

我发现James Padolsey's implementation 看起来很简单,但很好。该页面上显示的镜像方法上方的选择器格式。还有这个Sizzle patch。

出于某种原因,我记得不久前读过 jQuery 1.4 将支持对 jquery .data() 对象中的值的选择器。然而,现在我正在寻找它,我找不到它。也许这只是我看到的一个功能请求。是否对此有支持,我只是没有看到它?

理想情况下,我希望使用点符号支持 data() 中的子属性。像这样:

$('a').data("user",name: first:"Tom",last:"Smith",username: "tomsmith");
$('a[:user.name.first=Tom]');

我还想支持多个数据选择器,其中只找到具有所有指定数据选择器的元素。常规的 jquery 多重选择器执行 OR 操作。例如,$('a.big, a.small') 选择具有类bigsmalla 标签)。我正在寻找 AND,可能是这样的:

$('a').data("artist",id: 3281, name: "Madonna");
$('a').data("category","music");
$('a[:category=music && :artist.name=Madonna]');

最后,如果比较运算符和正则表达式功能可用于数据选择器,那就太好了。所以$(a[:artist.id>5000]) 是可能的。我意识到我可能可以使用filter() 完成大部分工作,但最好有一个简单的选择器格式。

有哪些解决方案可以做到这一点?詹姆斯的 Padolsey 是目前最好的解决方案吗?我关心的主要是性能,还有额外的特性,比如子属性点表示法和多个数据选择器。是否有其他实现支持这些东西或在某些方面更好?

【问题讨论】:

使用 jquery ui core api.jqueryui.com/category/ui-core 它有一个 :data() 选择器 【参考方案1】:

有一个 :data() filter plugin 就是这样做的 :)

基于您的问题的一些示例:

$('a:data("category=music")')
$('a:data("user.name.first=Tom")');
$('a:data("category=music"):data("artist.name=Madonna")');
//jQuery supports multiple of any selector to restrict further, 
//just chain with no space in-between for this effect

可能的相比,性能不会非常好,从$._cache 中选择并抓取相应的元素是迄今为止最快的,但更多的是迂回而不是就你如何获得东西而言非常“jQuery-ey”(你通常从元素方面进来)。在我的脑海中,我不确定这是不是最快的,因为从唯一 ID 到元素的过程本身就性能而言是复杂的。

您提到的比较选择器最好在.filter() 中进行,插件中没有对此的内置支持,尽管您可以轻松添加它。

【讨论】:

感谢您的详尽回答。你知道如果使用 html5 data-* 属性并选择它们会比选择 .data() 属性更快吗?另外,知道在哪里可以找到有关 $._cache 的更多信息吗?我用谷歌搜索了它,但没有找到太多。 @Tauren - 我的错是$.cache 而不是$._cache,你可以在这里看到它是如何在jQuery 核心中实现和使用的:github.com/jquery/jquery/blob/master/src/data.js#L4 当你调用.data() 时,它实际上将它存储为$.cache[elementUniqueID] 中的对象,它是根据需要以增量方式分配给每个元素的 ID,例如 1、2、3 等。我相信,基于 git cmets,该攀爬 ID 将在 jQuery 1.4.3 中公开另一天。我会假设 HTML 5 路线会更快,这取决于可用的浏览器优化(我相信会有更多可用)。【参考方案2】:

我创建了一个新的data 选择器,它应该使您能够执行嵌套查询和 AND 条件。用法:

$('a:data(category==music,artist.name==Madonna)');

模式是:

:data( namespace [operator check]  )

“操作员”和“检查”是可选的。因此,如果您只有:data(a.b.c),它只会检查a.b.c真实性

您可以在下面的代码中看到可用的运算符。其中包括~=,它允许进行正则表达式测试:

$('a:data(category~=^mus..$,artist.name~=^M.+a$)');

我已经用一些变化对其进行了测试,它似乎工作得很好。我可能会很快将其添加为 Github 存储库(带有完整的测试套件),所以请留意!

代码:

(function()

    var matcher = /\s*(?:((?:(?:\\\.|[^.,])+\.?)+)\s*([!~><=]=|[><])\s*("|')?((?:\\\3|.)*?)\3|(.+?))\s*(?:,|$)/g;

    function resolve(element, data) 

        data = data.match(/(?:\\\.|[^.])+(?=\.|$)/g);

        var cur = jQuery.data(element)[data.shift()];

        while (cur && data[0]) 
            cur = cur[data.shift()];
        

        return cur || undefined;

    

    jQuery.expr[':'].data = function(el, i, match) 

        matcher.lastIndex = 0;

        var expr = match[3],
            m,
            check, val,
            allMatch = null,
            foundMatch = false;

        while (m = matcher.exec(expr)) 

            check = m[4];
            val = resolve(el, m[1] || m[5]);

            switch (m[2]) 
                case '==': foundMatch = val == check; break;
                case '!=': foundMatch = val != check; break;
                case '<=': foundMatch = val <= check; break;
                case '>=': foundMatch = val >= check; break;
                case '~=': foundMatch = RegExp(check).test(val); break;
                case '>': foundMatch = val > check; break;
                case '<': foundMatch = val < check; break;
                default: if (m[5]) foundMatch = !!val;
            

            allMatch = allMatch === null ? foundMatch : allMatch && foundMatch;

        

        return allMatch;

    ;

());

【讨论】:

@J-P:非常甜蜜,我知道我可以依靠你!现在要睡觉了,但我明天会试试看。是否也可以进行 OR 操作?我不需要它,只是好奇。 @J-P:另外,我很好奇您对其他数据选择器解决方案的看法,以及您与他们的优缺点。比如这个插件:plugins.jquery.com/project/dataSelector. 可以进行 OR 操作,但最好有两个选择器,$("a:data(condition),a:data(orCondition)") ...它会产生相同的效果。添加的功能越多,速度就越慢。如果逻辑复杂,则使用$(foo).filter(function()...) @J-P:你有没有把它变成一个 github 项目?我正在使用 jQuery 1.5.1 运行测试,在带有 html5 属性 data-test="500" 的输入上使用选择器 $("input:data(test>400)") 但选择器没有返回任何内容。跨度> @JamesSouth 那是因为这个答案中的选择器使用了低级别的jQuery.data,它没有获取HTML5属性中定义的数据。如果您想要该功能,可以将 jQuery.data 更改为 $('selector').data,但这是为了速度而做出的权衡。【参考方案3】:

目前我是这样选择的:

$('a[data-attribute=true]')

这似乎工作得很好,但如果 jQuery 能够在没有 'data-' 前缀的情况下通过该属性进行选择,那就太好了。

我没有使用通过 jQuery 动态添加到元素的数据来测试这个,所以这可能是这个方法的失败。

【讨论】:

这正是我想要的。甜 如果你通过 .data() 函数通过 JS 附加/修改数据,这实际上不起作用,属性选择器只检查 DOM,JS 将 .data() 存储在内存中 如果您通过 .data() 附加,您能否告诉您如何按属性访问? 我建议这个线程中提供的其他答案对于非常简单的用例以外的任何事情都是更好的选择。 Dmitri 的解决方案在我看来不错,因为它不依赖第三方代码。【参考方案4】:

我想警告你 $('a[data-attribute=true]') 不起作用,根据 Ashley 的回复,如果你通过 data() 函数将数据附加到 DOM 元素。

如果您在 HTML 中添加一个实际的 data-attr,它会按预期工作,但是 jQuery 将数据存储在内存中,因此您从 $('a[data-attribute=true]') 获得的结果将不正确。

您需要使用数据插件 http://code.google.com/p/jquerypluginsblog/,使用 Dmitri 的 filter 解决方案,或者对所有元素执行 $.each 并反复检查 .data()

【讨论】:

就我而言,这很好,因为我在服务器端预先填充了该字段,并且只需要在初始加载时以这种方式查询它。过滤器可能同样快(几乎可以肯定每个都慢),但这在可读性方面获胜。【参考方案5】:

您也可以使用简单的过滤功能,无需任何插件。这不是你想要的,但结果是一样的:

$('a').data("user", name: first:"Tom",last:"Smith",username: "tomsmith");

$('a').filter(function() 
    return $(this).data('user') && $(this).data('user').name.first === "Tom";
);

【讨论】:

这是个好主意,我忘了filter 遍历函数可以接受测试函数 =) 谢谢 我怎么能做一个“包含”而不是等于汤姆? Alisso,而不是 name.first == "Tom" 使用 name.first && name.first.indexOF("Tom") > -1;【参考方案6】:

如果您还使用 jQueryUI,您将获得一个(简单)版本的 :data 选择器,用于检查数据项的存在,因此您可以执行 $("div:data(view)")$( this ).closest(":data(view)") 之类的操作。

见http://api.jqueryui.com/data-selector/。我不知道他们有多久了,但它现在就在那里!

【讨论】:

这只会像你说的那样检查数据项的存在。它不检查值(根据文档)。很高兴知道这一点【参考方案7】:

您可以使用attr() 在榆树上设置data-* 属性,然后使用该属性进行选择:

var elm = $('a').attr('data-test',123); //assign 123 using attr()
elm = $("a[data-test=123]"); //select elm using attribute

现在对于那棵榆树,attr()data() 都将产生 123

console.log(elm.attr('data-test')); //123
console.log(elm.data('test')); //123

但是,如果您使用 attr() 将值修改为 456data() 仍将是 123

elm.attr('data-test',456); //modify to 456
elm = $("a[data-test=456]"); //reselect elm using new 456 attribute

console.log(elm.attr('data-test')); //456
console.log(elm.data('test')); //123

据我了解,如果您不需要,您可能应该避免在代码中混合 attr()data() 命令。因为attr() 似乎直接与 DOM 对应,而data() 与“内存”交互,尽管它的初始值可以来自 DOM。但关键是两者根本不一定同步。

所以小心点。

无论如何,如果您不更改 DOM 或内存中的 data-* 属性,那么您不会有问题。一旦您开始修改值,就会出现潜在问题。

感谢@Clarence Liu 对@Ash 的回答,以及this post。

【讨论】:

【参考方案8】:

这是一个简化生活的插件https://github.com/rootical/jQueryDataSelector

这样使用它:

data selector           jQuery selector
  $$('name')              $('[data-name]')
  $$('name', 10)          $('[data-name=10]')
  $$('name', false)       $('[data-name=false]')
  $$('name', null)        $('[data-name]')
  $$('name', )          Syntax error

【讨论】:

【参考方案9】:
$('a[data-category="music"]')

它有效。见Attribute Equals Selector [name=”value”]。

【讨论】:

以上是关于jquery 数据选择器的主要内容,如果未能解决你的问题,请参考以下文章

jQuery选择器。 5.21 《深夜还在编码的你》

jquery (1.8.2) 数据选择器

JavaScript之jQuery-2 jQuery选择器(jQuery选择器基本选择器层次选择器过滤选择器表单选择器)

jQuery之选择器

jQuery 如何通过 ID 选择器 获取动态ID

jQuery 选择器没有特定的数据属性