jQuery数据选择器


184

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

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

或者选择器将采用常规属性选择器格式:

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

或采用属性格式,但带有说明符以指示其位于.data()

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

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

出于某种原因,我记得有一阵子,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')选择a具有class big或的标签small。我正在寻找AND,也许是这样的:

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

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

有哪些解决方案可以做到这一点?Jame's Padolsey目前是最好的解决方案吗?我主要关心的是性能,还涉及子特性点表示法和多个数据选择器等额外功能。是否有其他支持这些功能或在某种程度上更好的实现?


使用jquery ui核心api.jqueryui.com/category/ui-core 它具有:data()选择器
regisbsb

Answers:


101

我创建了一个新的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;

    };

}());

@JP:非常可爱,我知道我可以指望你!现在就去睡觉,但是明天我会尝试的。是否可以进行“或”运算?我不需要,只是好奇。
牛头人2010年

1
@JP:另外,我很好奇您对其他数据选择器解决方案的看法,这对您的利弊是有帮助的。例如,此插件: plugins.jquery.com/project/dataSelector
牛头人2010年

1
可以进行“或”运算,但最好是简单地具有两个选择器,$("a:data(condition),a:data(orCondition)")...将具有相同的效果。添加的功能越多,速度就越慢。如果逻辑很复杂,请使用$(foo).filter(function(){...})
詹姆斯

3
@JP:您曾经把它变成一个github项目吗?我正在使用jQuery 1.5.1在html5属性data-test =“ 500”的输入上使用选择器$(“ input:data(test> 400)”)进行测试,但选择器未返回任何内容。
詹姆斯·南

1
@JamesSouth这是因为此答案中的选择器使用了低级jQuery.data,它没有获取HTML5属性中定义的数据。如果您需要该功能,则可以更改jQuery.data$('selector').data,但这是在速度上的权衡。
Shef,2011年

175

此刻我正在选择这样的:

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

这看起来似乎很好,但是如果jQuery能够通过没有'data-'前缀的属性进行选择,那将是很好的选择。

我还没有使用通过jQuery动态添加到元素中的数据来测试这一点,所以这可能是该方法的缺点。


这正是我想要的。甜
MikeMurko

109
如果您通过.data()函数通过JS附加/修改数据,则此方法实际上不起作用,属性选择器仅检查DOM,JS将.data()存储在内存中
Clarence Liu

1
如果通过.data()附加,您能否告诉您如何按属性访问?
Maxim V. Pavlov 2012年

1
我建议,除了非常简单的用例之外,此线程中提供的其他答案对于其他任何事情都是更好的选择。
2012年

Dmitri的解决方案对我来说看起来不错,因为它不依赖于第三方代码。
2012年

83

您也可以使用没有任何插件的简单过滤功能。这不是您想要的,但是结果是相同的:

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

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

2
这是一个好主意,我忘记了filter遍历函数可以接受测试函数=)谢谢
Clarence Liu

我该如何做一个“包含”而不是等于汤姆?
Alisso

1
别名,而不是name.first ==“ Tom”,请使用name.first && name.first.indexOF(“ Tom”)> -1;
Dmitri

24

$('a[data-attribute=true]')如果您通过data()函数将数据附加到DOM元素,我想警告您,按照Ashley的答复,这是行不通的。

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

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


就我而言,这很好,因为我已在服务器端预填充了该字段,只需要在初始加载时以这种方式进行查询。过滤器可能也一样快(几乎可以肯定每个过滤器都比较慢),但这赢得了可读性。
唐·

11

有一个:data()过滤器插件可以做到这一点:)

根据您的问题的一些示例:

$('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的安永”东西(您通常从元素一侧进来)。我不敢肯定这是最快的,因为就性能而言,从唯一ID到元素的转换过程本身就很复杂。

您提到的比较选择器最好在中进行.filter(),插件中没有对此的内置支持,尽管您可以添加它而不会带来很多麻烦。


感谢您的详尽回答。您知道使用HTML5 data-*属性并在其上进行选择是否比在.data()属性上进行选择更快?另外,有什么想法可以在哪里找到有关$ ._ cache的更多信息?我用谷歌搜索,但没有找到太多。
牛头人2010年

@Tauren-我的错$.cache不是$._cache,您可以在这里查看它在jQuery核心中的实现和使用方式:github.com/jquery/jquery/blob/master/src/data.js#L4 当您调用.data()它实际上是将其存储为一个对象在中$.cache[elementUniqueID],这是按需要以递增方式分配给每个元素(例如1、2、3等)的ID。我相信,攀爬ID将在jQuery 1.4.3中公开,我相信这是基于前几天的git注释。我认为HTML 5路由会更快,这取决于可用的浏览器优化(我相信还会有更多的优化)。
尼克·克拉弗

7

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

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

但是,如果使用值修改为456attr()data() 则仍为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()似乎data()其初始值可以来自DOM,但它似乎与DOM直接对应,而与“内存”交互。但是关键是两者不一定完全同步。

因此,请小心。

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

感谢@Clarence Liu对@Ash的回答以及这篇文章



5

如果您还使用jQueryUI,则会获得:data选择器的(简单)版本,该选择器会检查数据项的存在,因此可以执行$("div:data(view)"),或$( this ).closest(":data(view)")

请参阅http://api.jqueryui.com/data-selector/。我不知道他们已经住了多久了,但是现在在那里!


就像您说的那样,这仅检查数据项的存在。它不检查值(根据文档)。很高兴知道这一点
Fractalf

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.