jquery veri seçici


184

Bir öğenin .data()nesnesinde depolanan değerlere dayalı öğeleri seçmek gerekir . En azından, belki de bunun gibi seçicileri kullanarak en üst düzey veri özelliklerini seçmek istiyorum:

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

Veya belki de seçici normal nitelik seçici formatında olacaktır:

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

Veya özellik biçiminde, ancak içinde olduğunu belirtmek için bir belirteçle .data():

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

James Padolsey'in uygulamasını basit ama iyi görünmek için buldum . Seçici biçimleri, o sayfada gösterilen yansıtma yöntemlerinin üstündedir. Ayrıca bu Sizzle yaması var .

Nedense, jQuery 1.4 jquery .data()nesnesindeki değerleri seçiciler için destek içereceğini bir süre geri hatırlıyorum . Ancak, şimdi aradığım için bulamıyorum. Belki de sadece gördüğüm bir özellik isteğiydi. Bunun için bir destek var mı ve sadece görmüyorum?

İdeal olarak, nokta gösterimini kullanarak veri () alt özelliklerini desteklemek istiyorum. Bunun gibi:

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

Ayrıca, yalnızca TÜM belirtilen veri seçicilere sahip öğelerin bulunduğu birden fazla veri seçiciyi desteklemek istiyorum. Normal jquery çoklu seçici OR işlemi yapar. Örneğin, sınıf veya ) içeren etiketleri $('a.big, a.small')seçer . Bir AND arıyorum, belki de böyle:abigsmall

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

Son olarak, veri seçicilerinde karşılaştırma işleçlerinin ve normal ifade özelliklerinin bulunması harika olurdu. Bu $(a[:artist.id>5000])mümkün olur. Muhtemelen bunu kullanarak yapabileceğimin farkındayım filter(), ama basit bir seçici formata sahip olmak güzel olurdu.

Bunu yapmak için hangi çözümler var? Jame's Padolsey şu anda en iyi çözüm mü? Benim endişem öncelikle performans açısından değil, aynı zamanda alt özellik nokta gösterimi ve çoklu veri seçiciler gibi ekstra özellikler. Bunları destekleyen ya da bir şekilde daha iyi olan başka uygulamalar var mı?


Jquery ui çekirdeğini kullanın api.jqueryui.com/category/ui-core a sahiptir: veri () seçici
regisbsb

Yanıtlar:


101

dataİç içe sorgulama ve AND koşulları yapmanızı sağlayacak yeni bir seçici oluşturdum . Kullanımı:

$('a:data(category==music,artist.name==Madonna)');

Desen:

:data( {namespace} [{operator} {check}]  )

"operatör" ve "kontrol" isteğe bağlıdır. Yani, sadece varsa :data(a.b.c)basitçe kontrol edecektir doğruluğuna ait a.b.c.

Kullanılabilir operatörleri aşağıdaki kodda görebilirsiniz. Bunların arasında ~=regex testine izin veren:

$('a:data(category~=^mus..$,artist.name~=^M.+a$)');

Birkaç varyasyon ile test ettim ve oldukça iyi çalışıyor gibi görünüyor. Muhtemelen yakında bir Github repo olarak ekleyeceğim (tam bir test paketi ile), bu yüzden bir göz atın!

Kod:

(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: Çok tatlı, sana güvenebileceğimi biliyordum! Şimdi yatağa yöneldim, ama yarın deneyeceğim. VEYA işlemleri de yapmak mümkün müdür? Buna ihtiyacım yok, sadece merak ediyorum.
Tauren

1
@JP: Ayrıca, sizinkine karşı diğer veri seçici çözümlerini, artılarını / eksilerini almayı merak ediyorum. Örneğin, bu eklenti: plugins.jquery.com/project/dataSelector .
Tauren

1
VEYA işlemleri yapmak mümkündür, ancak iki seçiciye sahip olmak en iyisi olabilir, $("a:data(condition),a:data(orCondition)")... aynı etkiye sahip olacaktır. Ne kadar çok özellik eklerseniz, o kadar yavaş olur. Mantık karmaşıksa, kullanın $(foo).filter(function(){...}).
James

3
@JP: Bunu hiç bir github projesine dönüştürdünüz mü? Html5 özniteliği data-test = "500" olan bir girdide $ ("input: data (test> 400)") seçicisini kullanarak jQuery 1.5.1 kullanarak bir test çalıştırıyorum, ancak seçici hiçbir şey döndürmüyor.
James South

1
@JamesSouth Bunun nedeni, bu yanıttaki seçicinin jQuery.dataHTML5 özniteliklerinde tanımlanan verileri almayan düşük düzeyi kullanmasıdır . Eğer bu işlevselliği istiyorsanız, değiştirebilir jQuery.dataiçin $('selector').data, ama bu hız için kapalı bir ticaret.
Shef

175

Şu anda böyle seçiyorum:

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

Bu gayet iyi çalışıyor gibi görünüyor, ancak jQuery 'data-' öneki olmadan bu özellik tarafından seçilebilseydi iyi olurdu.

Bu jQuery aracılığıyla öğelere dinamik olarak eklenen verilerle test etmedim, bu yüzden bu yöntemin çöküşü olabilir.


Tam da aradığım şey buydu. Sweet
MikeMurko

109
.Data () işlevi aracılığıyla JS aracılığıyla veri ekler / değiştirirseniz, bu özellik çalışmaz; öznitelik seçici yalnızca DOM, JS depolar .data () bellekte kontrol eder
Clarence Liu

1
.Data () ile eklerseniz, özelliğe göre nasıl erişebileceğinizi söyler misiniz?
Maxim V.Pavlov

1
Bu konuda verilen diğer cevapların çok basit bir kullanım durumundan başka bir şey için daha iyi bir seçenek olduğunu öneriyorum.
Ash

Dmitri'nin çözümü, üçüncü taraf kodlarına bağlı olmadığı için bana iyi görünüyor.
Ash

83

Herhangi bir eklenti olmadan basit bir filtreleme işlevi de kullanabilirsiniz. Bu tam olarak istediğiniz şey değil, sonuç aynı:

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

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

2
Bu harika bir fikir, filtergeçiş fonksiyonunun bir test fonksiyonunu kabul edebileceğini unuttum =) teşekkürler
Clarence Liu

Tom'a eşit yerine "içerir" i nasıl yapabilirim?
Alisso

1
Alisso, name.first == "Tom" yerine name.first && name.first.indexOF ("Tom")> -1;
Dmitri

24

$('a[data-attribute=true]')Veri () işlevi aracılığıyla bir DOM öğesine veri eklediyseniz, Ashley cevabına göre, işe yaramadığı konusunda sizi uyarmak istiyorum .

HTML'nize gerçek bir data-attr eklemenizi beklediğiniz gibi çalışır, ancak jQuery verileri bellekte saklar, böylece alacağınız sonuçlar $('a[data-attribute=true]')doğru olmaz.

Http://code.google.com/p/jquerypluginsblog/ veri eklentisini kullanmanız filter, Dmitri'nin çözümünü kullanmanız veya tüm öğeler üzerinde bir $ .each yapmanız ve .data () öğesini tekrar tekrar kontrol etmeniz gerekir.


Benim durumumda, sunucu tarafındaki alanı önceden doldurduğum ve sadece ilk yükte bu şekilde danışmam gerektiğinden iyi. Filtre muhtemelen aynı derecede hızlıdır (her biri neredeyse kesinlikle daha yavaştır), ancak bu okunabilirlik kazanır.
Don

11

Sadece bunu yapan bir :data()filtre eklentisi var :)

Sorunuza dayalı bazı örnekler:

$('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

Performans, mümkün olanlara kıyasla son derece iyi olmayacak $._cache, karşılık gelen unsurlardan seçim yapmak ve kapmak çok hızlı, ancak çok daha yuvarlak ve çok "jQuery-ey" değil. şeyler (genellikle eleman tarafından geliyorsun). Başımın en tepesinden, bunun en hızlı olduğundan emin değilim çünkü benzersiz id'den öğeye gitme süreci performans açısından kendi içinde kıvrımlıdır.

Bahsettiğiniz karşılaştırma seçici a'da en iyisi olacaktır .filter(), eklentide bunun için yerleşik bir destek yoktur, ancak çok fazla sorun olmadan ekleyebilirsiniz.


kapsamlı cevap için teşekkürler. HTML5 data-*özniteliklerini kullanmanın ve bunları seçmenin, .data()mülkleri seçmekten daha hızlı olacağını biliyor musunuz ? Ayrıca, $ ._ cache hakkında nereden daha fazla bilgi edinebilirim? Bunun için googledim, ancak fazla bir şey bulamıyorum.
Tauren

- @Tauren Benim öyle arıza $.cachedeğil $._cache: Eğer uygulanacak ve burada jQuery çekirdek nasıl kullanıldığını görebilirsiniz github.com/jquery/jquery/blob/master/src/data.js#L4 Aradığınızda .data()aslında bir nesne olarak depolamak oluyor içinde $.cache[elementUniqueID], her öğeye, örneğin 1, 2, 3, vb. HTML 5 rotasının daha hızlı olacağını varsayalım, hangi tarayıcı optimizasyonlarının mevcut olduğuna bağlı (daha fazla kullanılabilir olacağından eminim).
Nick Craver

7

data-*Kullanarak bir karaağaç üzerinde bir öznitelik ayarlayabilir attr()ve daha sonra bu özniteliği kullanarak seçim yapabilirsiniz:

var elm = $('a').attr('data-test',123); //assign 123 using attr()
elm = $("a[data-test=123]"); //select elm using attribute

ve şimdi o karaağaç için, hem attr()ve data()verecektir 123 :

console.log(elm.attr('data-test')); //123
console.log(elm.data('test')); //123

Olmak değerini değiştirmek Ancak, 456 kullanarak attr(), data() hala olacaktır 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

Anladığım kadarıyla, muhtemelen kodunuzda interming attr()ve data()komutlardan uzak durmalısınız . Çünkü attr()doğrudan DOM ile örtüşüyor gibi görünüyor data(), ancak 'hafıza' ile etkileşime giriyor, ancak başlangıç ​​değeri DOM'dan olabilir. Ancak kilit nokta, ikisinin mutlaka senkronize olmamasıdır.

Bu yüzden dikkatli ol.

Her halükarda data-*, DOM'daki veya bellekteki özniteliği değiştirmiyorsanız, sorun yaşamayacaksınız. Değerleri değiştirmeye başlar başlamaz potansiyel sorunların ortaya çıkabileceği zamandır.

@Clarence Liu'ya @ Ash'in yanıtı ve bu gönderiye teşekkürler .



5

Ayrıca jQueryUI kullanıyorsanız, :dataseçicinin bir veri öğesinin varlığını kontrol eden (basit) bir sürümünü alırsınız , böylece gibi bir şey yapabilir $("div:data(view)")veya$( this ).closest(":data(view)") .

Bkz. Http://api.jqueryui.com/data-selector/ . Ne kadar süredir sahip olduklarını bilmiyorum, ama şimdi orada!


Bu yalnızca sizin belirttiğiniz gibi veri öğesinin varlığını kontrol eder. Değerleri kontrol etmez (dokümanlara göre). Bu konuda bilmek güzel
Fractalf

3

İşte hayatı kolaylaştıran bir eklenti https://github.com/rootical/jQueryDataSelector

Şöyle kullanın:

data selector           jQuery selector
  $$('name')              $('[data-name]')
  $$('name', 10)          $('[data-name=10]')
  $$('name', false)       $('[data-name=false]')
  $$('name', null)        $('[data-name]')
  $$('name', {})          Syntax error
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.