Селектор данных 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, а также этот пост.

Ответ 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