Селектор данных jquery - PullRequest
183 голосов
/ 23 мая 2010

Мне нужно выбрать элементы на основе значений, хранящихся в объекте .data() элемента. Как минимум, я хотел бы выбрать свойства данных верхнего уровня с помощью селекторов, возможно, так:

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

Или, возможно, селектор будет в обычном формате селектора атрибутов:

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

Или в формате атрибута, но с указателем, указывающим, что он находится в .data():

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

Я нашел Реализацию Джеймса Падолси , чтобы выглядеть просто, но хорошо. Селекторные форматы выше зеркальных методов показаны на этой странице. Существует также этот патч Sizzle .

Почему-то я вспомнил, как читал некоторое время назад, что 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). Я ищу 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 лучшим решением на данный момент? В первую очередь меня беспокоит производительность, а также дополнительные функции, такие как точечная нотация под-свойства и несколько селекторов данных. Существуют ли другие реализации, которые поддерживают эти вещи или лучше в некотором роде?

Ответы [ 9 ]

175 голосов
/ 06 июля 2011

На данный момент я выбираю вот так:

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

Что, кажется, работает нормально, но было бы неплохо, если бы jQuery мог выбирать по этому атрибуту без префикса 'data-'.

Я не проверял это с данными, добавляемыми в элементы динамически через jQuery, так что это может привести к падению этого метода.

102 голосов
/ 24 мая 2010

Я создал новый селектор 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;

    };

}());
83 голосов
/ 06 апреля 2012

Вы также можете использовать простую функцию фильтрации без каких-либо плагинов. Это не совсем то, что вы хотите, но результат тот же:

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

$('a').filter(function() {
    return $(this).data('user') && $(this).data('user').name.first === "Tom";
});
24 голосов
/ 06 февраля 2012

Я хочу предупредить вас, что $('a[data-attribute=true]') не работает, согласно ответу Эшли, если вы прикрепили данные к элементу DOM через функцию data ().

Это работает так, как вы ожидаете, если вы добавите фактический data-attr в ваш HTML, но jQuery хранит данные в памяти, поэтому результаты, которые вы получите из $('a[data-attribute=true]'), будут неверными.

Вам нужно будет использовать плагин данных http://code.google.com/p/jquerypluginsblog/,, использовать решение Дмитрия filter или выполнить $ .each для всех элементов и проверять .data () итеративно

11 голосов
/ 23 мая 2010

Есть :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-эй» с точки зрения того, какВы добираетесь до вещей (вы обычно входите со стороны элемента).В общем, я не уверен, что это так быстро, так как процесс перехода от уникального идентификатора к элементу запутан сам по себе с точки зрения производительности.

Упомянутый вами селектор сравнения будет лучшимЧтобы сделать это в .filter(), в плагине нет встроенной поддержки для этого, хотя вы можете добавить его без особых проблем.

7 голосов
/ 11 апреля 2013

Вы можете установить атрибут 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, а также этот пост .

6 голосов
/ 18 июня 2015
$('a[data-category="music"]')

Это работает. См. Селектор равных атрибутов [name = ”value”] .

5 голосов
/ 11 января 2013

Если вы также используете jQueryUI, вы получаете (простую) версию селектора :data, которая проверяет наличие элемента данных, поэтому вы можете сделать что-то вроде $("div:data(view)") или $( this ).closest(":data(view)").

См. http://api.jqueryui.com/data-selector/. Я не знаю, как долго это было у них, но оно есть сейчас!

3 голосов
/ 26 января 2014

Вот плагин, который упрощает жизнь 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...