183 votes

sélecteur de données jquery

J'ai besoin de sélectionner des éléments sur la base de valeurs stockées dans l'élément .data() objet. Au minimum, j'aimerais sélectionner des propriétés de données de premier niveau à l'aide de sélecteurs, par exemple de la manière suivante :

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

Ou alors, le sélecteur se présenterait sous la forme d'un sélecteur d'attributs ordinaire :

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

Ou au format attribut, mais avec un spécificateur indiquant qu'il s'agit d'un format .data() :

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

J'ai trouvé Mise en œuvre de James Padolsey pour avoir l'air simple, mais bon. Les formats de sélecteurs ci-dessus reflètent les méthodes présentées sur cette page. Il y a aussi ceci Patch Sizzle .

Pour une raison ou une autre, je me souviens avoir lu il y a quelque temps que jQuery 1.4 inclurait la prise en charge des sélecteurs sur les valeurs dans l'interface jquery .data() objet. Cependant, maintenant que je le cherche, je ne le trouve pas. Peut-être s'agissait-il d'une demande de fonctionnalité que j'ai vue. Y a-t-il un support pour cela et je ne le vois pas ?

Idéalement, j'aimerais prendre en charge les sous-propriétés dans data() en utilisant la notation par points. Comme ceci :

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

J'aimerais également prendre en charge plusieurs sélecteurs de données, de sorte que seuls les éléments correspondant à TOUS les sélecteurs de données spécifiés soient trouvés. Le sélecteur multiple habituel de jquery effectue une opération OU. Par exemple, $('a.big, a.small') sélectionne a avec l'une ou l'autre des classes big o small ). Je cherche un ET, peut-être comme ceci :

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

Enfin, il serait bon que les opérateurs de comparaison et les fonctions regex soient disponibles sur les sélecteurs de données. Ainsi, les $(a[:artist.id>5000]) serait possible. Je me rends compte que je pourrais probablement faire une grande partie de ce travail en utilisant le système d'information de la Commission. filter() mais il serait bon d'avoir un format de sélecteur simple.

Quelles sont les solutions disponibles pour y parvenir ? Jame's Padolsey's est-elle la meilleure solution à l'heure actuelle ? Mon inquiétude porte principalement sur les performances, mais aussi sur les fonctionnalités supplémentaires telles que la notation par points des sous-propriétés et les sélecteurs de données multiples. Existe-t-il d'autres implémentations qui prennent en charge ces éléments ou qui sont meilleures d'une manière ou d'une autre ?

175voto

Ash Points 1745

Pour l'instant, je sélectionne comme suit :

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

Cela semble fonctionner parfaitement, mais il serait bon que jQuery puisse sélectionner par cet attribut sans le préfixe "data-".

Je n'ai pas testé cette méthode avec des données ajoutées aux éléments via jQuery de manière dynamique, ce qui pourrait être l'inconvénient de cette méthode.

102voto

James Points 56229

J'ai créé un nouveau data qui devrait vous permettre d'effectuer des requêtes imbriquées et des conditions AND. Utilisation :

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

Le modèle est le suivant :

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

Les termes "operator" et "check" sont facultatifs. Ainsi, si vous n'avez que :data(a.b.c) il vérifiera simplement la présence de l'élément vérité de a.b.c .

Vous pouvez voir les opérateurs disponibles dans le code ci-dessous. Parmi eux, on trouve ~= qui permet de tester les expressions rationnelles :

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

Je l'ai testé avec quelques variantes et il semble fonctionner assez bien. Je vais probablement ajouter ceci en tant que repo Github bientôt (avec une suite de tests complète), alors restez à l'affût !

Le code :

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

    };

}());

83voto

Dmitri Points 1167

Vous pouvez également utiliser une fonction de filtrage simple sans aucun plugin. Ce n'est pas exactement ce que vous voulez, mais le résultat est le même :

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

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

24voto

Clarence Liu Points 2062

Je tiens à vous avertir que $('a[data-attribute=true]') ne fonctionne pas, selon la réponse d'Ashley, si vous avez attaché des données à un élément DOM via la fonction data().

Le fonctionnement est le même que si vous aviez ajouté un data-attr dans votre HTML, mais jQuery stocke les données en mémoire, de sorte que les résultats que vous obtiendriez à partir de $('a[data-attribute=true]') ne serait pas correcte.

Vous devez utiliser le plugin de données http://code.google.com/p/jquerypluginsblog/ , utiliser le filter ou faire un $.each sur tous les éléments et vérifier .data() itérativement

11voto

Nick Craver Points 313913

Il y a un :data() plugin de filtrage qui fait exactement cela :)

Quelques exemples en fonction de votre question :

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

Les performances ne seront pas extrêmement élevées par rapport à ce qui se fait dans le monde entier. possible , en choisissant parmi $._cache et saisir les éléments correspondants est de loin la solution la plus rapide, mais elle est beaucoup plus détournée et n'est pas très "jQuery-ey" en ce qui concerne la manière d'accéder aux éléments (vous arrivez généralement du côté des éléments). De toute façon, je ne suis pas sûr que cette méthode soit la plus rapide, car le processus qui consiste à passer d'un identifiant unique à un élément est en soi compliqué, en termes de performances.

Le sélecteur de comparaison que vous avez mentionné sera plus facile à réaliser dans un fichier .filter() il n'y a pas de support intégré pour cela dans le plugin, bien que vous puissiez l'ajouter sans trop de problèmes.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X