Jquery 数据选择器

我需要根据元素的 .data()对象中存储的值来选择元素。至少,我希望使用选择器选择顶级数据属性,比如:

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

或者,选择器可能采用常规属性选择器格式:

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

或者是属性格式,但是有一个说明符来表明它是在 .data()中:

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

我发现 詹姆斯・帕多尔西的实现看起来很简单,但是很好。该页面上显示的上述镜像方法的选择器格式。还有这个 时髦贴片

出于某种原因,我记得前段时间读到过,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()来完成大部分工作,但是最好有一个简单的选择器格式。

有什么解决方案可以做到这一点?詹姆斯的帕多尔西是目前最好的解决方案吗?我关心的主要是性能,但也包括额外的特性,如子属性点符号和多个数据选择器。是否有其他实现支持这些东西,或者在某些方面更好?

143060 次浏览

有一个 :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-ey”(你通常从元素端进入)。在我的头脑中,我不确定这是否是最快的,因为从唯一 Id 到元素的过程本身就是一个复杂的过程,就性能而言。

你提到的比较选择器最好在 .filter()中使用,插件中没有内置的支持,不过你可以毫不费力地添加它。

我已经创建了一个新的 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 repo 添加进来(带有一个完整的测试套件) ,所以请继续关注!

密码:

(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;


};


}());

现在我的选择是这样的:

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

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

我还没有通过 jQuery 动态地将数据添加到元素中来测试这个方法,所以这可能是这个方法的缺陷。

我想提醒你,如果你通过 data ()函数将数据附加到 DOM 元素上,那么按照 Ashley 的回复,$('a[data-attribute=true]')不起作用。

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

您将需要使用数据插件 http://code.google.com/p/jquerypluginsblog/,使用 Dmitri 的 filter解决方案,或者执行 $。检查所有的元素。Data ()迭代

你也可以使用一个简单的过滤函数而不需要任何插件。这不完全是你想要的,但结果是一样的:

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


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

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

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

可以使用 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()将值修改为 456,则 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()似乎与 DOM 直接对应,而 data()与“内存”交互,尽管它的初始值可以来自 DOM。但关键的一点是,这两者并不一定是同步的。

所以小心点。

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

感谢@Clarence Liu 给@Ash 的回答,也感谢 这篇文章

这里有一个插件,简化生活 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
$('a[data-category="music"]')

成功了,见 属性等于选择器[ name = “ value”]