Селектор данных jquery
Мне нужно выбрать элементы на основе значений, хранящихся в объекте .data()
. Как минимум, я хотел бы выбрать свойства данных верхнего уровня с помощью селекторов, возможно, вот так:
$('a').data("category","music");
$('a:data(category=music)');
Или, может быть, селектор будет в обычном формате селектора атрибутов:
$('a[category=music]');
Или в формате атрибута, но с указателем, чтобы указать, что он находится в .data()
:
$('a[:category=music]');
Я нашел реализацию Джеймса Падолси, чтобы выглядеть просто, но хорошо. Селектор форматирует выше методы зеркала, показанные на этой странице. Существует также Sizzle patch.
По какой-то причине я вспоминаю некоторое время назад, что jQuery 1.4 будет включать поддержку селекторов по значениям в объекте jQuery .data()
. Однако теперь, когда я ищу его, я не могу его найти. Возможно, это был просто запрос функции, который я видел. Есть ли поддержка для этого, и я просто не вижу его?
В идеале я хотел бы поддерживать под-свойства в data() с использованием точечной нотации. Вот так:
$('a').data("user",{name: {first:"Tom",last:"Smith"},username: "tomsmith"});
$('a[:user.name.first=Tom]');
Я также хотел бы поддерживать несколько селекторов данных, в которых найдены только элементы со всеми указанными селекторами данных. Регулярный множественный селектор jquery выполняет операцию ИЛИ. Например, $('a.big, a.small')
выбирает теги a
либо с классом big
, либо small
). Я ищу И, возможно, так:
$('a').data("artist",{id: 3281, name: "Madonna"});
$('a').data("category","music");
$('a[:category=music && :artist.name=Madonna]');
Наконец, было бы замечательно, если бы в селекторах данных были доступны операторы сравнения и регулярные выражения. Таким образом, $(a[:artist.id>5000])
было бы возможно. Я понимаю, что, возможно, я мог бы сделать большую часть этого, используя filter()
, но было бы неплохо иметь простой формат селектора.
Какие решения доступны для этого? Является ли Jame Padolsey лучшим решением в это время? Моя озабоченность связана прежде всего с производительностью, но также и с дополнительными функциями, такими как точечное обозначение субсайта и несколько селекторов данных. Существуют ли другие реализации, которые поддерживают эти вещи или чем-то лучше?
Ответы
Ответ 1
Я создал новый селектор data
, который должен позволить вам выполнять вложенные запросы и условия И. Использование:
$('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;
};
}());
Ответ 2
В данный момент я выбираю так:
$('a[data-attribute=true]')
Кажется, что все работает отлично, но было бы неплохо, если бы jQuery смог выбрать этот атрибут без префикса 'data-'.
Я не тестировал это с данными, добавленными в элементы через jQuery динамически, так что это может быть падение этого метода.
Ответ 3
Вы также можете использовать простую функцию фильтрации без каких-либо плагинов. Это не совсем то, что вы хотите, но результат тот же:
$('a').data("user", {name: {first:"Tom",last:"Smith"},username: "tomsmith"});
$('a').filter(function() {
return $(this).data('user') && $(this).data('user').name.first === "Tom";
});
Ответ 4
Я хочу предупредить вас, что $('a[data-attribute=true]')
не работает в соответствии с ответом Эшли, если вы привязали данные к элементу DOM с помощью функции data().
Он работает так, как вы ожидали бы, добавив фактический data-attr в свой HTML, но jQuery хранит данные в памяти, поэтому результаты, которые вы получили от $('a[data-attribute=true]')
, были бы неправильными.
Вам понадобится использовать плагин данных http://code.google.com/p/jquerypluginsblog/, использовать решение Dmitri filter
или выполнить $.each по всем элементам и проверить. data() итеративно
Ответ 5
Там есть :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" в условия того, как вы получаете материал (вы обычно приходите со стороны элемента). Из моей головы я не уверен, что это так быстро, так как процесс перехода от уникального идентификатора к элементу запутан сам по себе с точки зрения производительности.
Селектор сравнения, о котором вы упомянули, лучше всего делать в .filter()
, там нет встроенной поддержки для этого в плагине, хотя вы можете добавить его без особых проблем.
Ответ 6
Вы можете установить атрибут 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
Однако, если вы измените значение 456 с помощью attr()
, 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. Но ключевым моментом является то, что они не обязательно синхронизируются вообще.
Так что будьте осторожны.
В любом случае, если вы не изменяете атрибут data-*
в DOM или в памяти, тогда у вас не будет проблемы. Вскоре, когда вы начинаете изменять значения, возникают потенциальные проблемы.
Спасибо @Clarence Liu за ответ @Ash, а также этот пост.
Ответ 7
$('a[data-category="music"]')
Это работает. См. Селектор выбора атрибутов [ name= "значение" ].
Ответ 8
Если вы также используете jQueryUI, вы получаете (простую) версию селектора :data
с ним, который проверяет наличие элемента данных, поэтому вы можете сделать что-то вроде $("div:data(view)")
или $( this ).closest(":data(view)")
.
См. http://api.jqueryui.com/data-selector/. Я не знаю, как долго они были у него, но это сейчас!
Ответ 9
Здесь плагин, который упрощает жизнь 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