Comment puis-je obtenir un sélecteur à partir d'un objet jQuery

112
$("*").click(function(){
    $(this); // how can I get selector from $(this) ?
});

Existe-t-il un moyen facile d' obtenir un sélecteur$(this) ? Il existe un moyen de sélectionner un élément par son sélecteur, mais qu'en est-il d'obtenir le sélecteur à partir de l'élément ?

Fidilip
la source
Vous êtes simplement curieux de savoir pourquoi cela serait utile? Ce que vous dites ici (sémantiquement) est pour chaque élément référencé comme $ (this) ... l'élément lui-même est $ (this) donc le sélecteur n'est pas nécessaire. Vous avez l'objet ...
BenAlabaster
1
Vous vous rendez compte que le clic avec des éléments imbriqués en renverra plus d'un? div dans un corps, etc. ou suis-je trop fatigué à ce stade?
Mark Schultheiss
2
Il serait utile que vous puissiez décrire le «but final» de ce que vous essayez d'accomplir. Vous pourriez obtenir une meilleure aide de cette façon.
jessegavin
3
Un élément peut être sélectionné de multiples façons. Aussi, sélecteur! == chemin. Qu'espérez-vous faire de ces informations?
deceze
2
Cela peut être utile si vous avez déjà trouvé un élément JQuery et que vous utilisez un plugin / module / sous-programme, qui nécessite un sélecteur pour fonctionner (peut-être hors de votre contrôle).
Andy

Réponses:

57

Ok, donc dans un commentaire ci-dessus, le demandeur a Fidilipdit que ce qu'il cherchait vraiment est d'obtenir le chemin vers l'élément actuel.

Voici un script qui "grimpera" dans l'arborescence des ancêtres du DOM, puis construira un sélecteur assez spécifique incluant tout idou des classattributs sur l'élément cliqué.

Voyez-le fonctionner sur jsFiddle: http://jsfiddle.net/Jkj2n/209/

<!DOCTYPE html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<script>
    $(function() {
        $("*").on("click", function(e) {
          e.preventDefault();
          var selector = $(this)
            .parents()
            .map(function() { return this.tagName; })
            .get()
            .reverse()
            .concat([this.nodeName])
            .join(">");

          var id = $(this).attr("id");
          if (id) { 
            selector += "#"+ id;
          }

          var classNames = $(this).attr("class");
          if (classNames) {
            selector += "." + $.trim(classNames).replace(/\s/gi, ".");
          }

          alert(selector);
      });
    });
    </script>
</head>
<body>
<h1><span>I love</span> jQuery</h1>
<div>
  <p>It's the <strong>BEST THING</strong> ever</p>
  <button id="myButton">Button test</button>
</div>
<ul>
  <li>Item one
    <ul>
      <li id="sub2" >Sub one</li>
      <li id="sub2" class="subitem otherclass">Sub two</li>
    </ul>
  </li>
</ul>
</body>
</html>

Par exemple, si vous cliquez sur le 2e élément de liste imbriquée dans le code HTML ci-dessous, vous obtiendrez le résultat suivant:

HTML>BODY>UL>LI>UL>LI#sub2.subitem.otherclass

Jességavin
la source
2
Merci! J'utiliserai votre code avec une modification sur la jointure ... join(" > ");, me donnera les enfants immédiats et donc un chemin plus strict .
nonsensickle
FANTASTIQUE ... je vais l'utiliser pour mon extension chrome. Juste une chose, parfois id est utilisé avec deux-points ':' préfixé, que nous pouvons remplacer par '\\:'
Savaratkar
Bon appel @nonsensickle. J'ai mis à jour mon exemple et supprimé une instruction if également.
jessegavin
Le fragment de code ci-dessus ne renvoie pas de classes pour les objets SVG. Voici un jsFiddle qui fonctionne pour SVG: http://jsfiddle.net/mikemsq/vbykja4x/7/ .
mikemsq
32

:: AVERTISSEMENT ::
.selector est obsolète depuis la version 1.7, supprimé depuis la 1.9

L'objet jQuery a une propriété de sélecteur que j'ai vue en creusant dans son code hier. Je ne sais pas si elle est définie dans la documentation et à quel point elle est fiable (pour une épreuve future). Mais ça marche!

$('*').selector // returns *

Modifier : Si vous deviez trouver le sélecteur à l'intérieur de l'événement, ces informations devraient idéalement faire partie de l'événement lui-même et non de l'élément, car un élément pourrait avoir plusieurs événements de clic attribués via divers sélecteurs. Une solution serait d'utiliser un wrapper autour bind(), click()etc. pour ajouter des événements au lieu de l'ajouter directement.

jQuery.fn.addEvent = function(type, handler) {
    this.bind(type, {'selector': this.selector}, handler);
};

Le sélecteur est passé en tant que propriété d'un objet nommé selector. Accédez-y en tant que event.data.selector.

Essayons-le sur un balisage ( http://jsfiddle.net/DFh7z/ ):

<p class='info'>some text and <a>a link</a></p>​

$('p a').addEvent('click', function(event) {
    alert(event.data.selector); // p a
});

Avertissement : N'oubliez pas que, tout comme pour les live()événements, la propriété selector peut être invalide si les méthodes de traversée DOM sont utilisées.

<div><a>a link</a></div>

Le code ci-dessous ne fonctionnera PAS, car il liverepose sur la propriété selector qui dans ce cas est a.parent()- un sélecteur invalide.

$('a').parent().live(function() { alert('something'); });

Notre addEventméthode se déclenchera, mais vous verrez vous aussi le mauvais sélecteur - a.parent().

Anurag
la source
Je pense que c'est le meilleur que nous pouvons obtenir de jquery =). Peut-être que je trouverai une solution complète plus tard. Quoi qu'il en soit, cela peut être vraiment pratique, merci! =)
Fidilip
@MarkoDumic: Doit être obsolète. Le lien est maintenant mort et le suivre nous dit seulement:No Such jQuery Method Exists
hippietrail
12
@Levitikon Est-ce que vous votez vraiment contre une réponse vieille de trois ans parce qu'elle est maintenant obsolète?! Vous devriez en effet éditer la réponse et mettre un avertissement
A. Wolff
22

En collaboration avec @drzaus, nous avons mis au point le plugin jQuery suivant.

jQuery.getSelector

!(function ($, undefined) {
    /// adapted http://jsfiddle.net/drzaus/Hgjfh/5/

    var get_selector = function (element) {
        var pieces = [];

        for (; element && element.tagName !== undefined; element = element.parentNode) {
            if (element.className) {
                var classes = element.className.split(' ');
                for (var i in classes) {
                    if (classes.hasOwnProperty(i) && classes[i]) {
                        pieces.unshift(classes[i]);
                        pieces.unshift('.');
                    }
                }
            }
            if (element.id && !/\s/.test(element.id)) {
                pieces.unshift(element.id);
                pieces.unshift('#');
            }
            pieces.unshift(element.tagName);
            pieces.unshift(' > ');
        }

        return pieces.slice(1).join('');
    };

    $.fn.getSelector = function (only_one) {
        if (true === only_one) {
            return get_selector(this[0]);
        } else {
            return $.map(this, function (el) {
                return get_selector(el);
            });
        }
    };

})(window.jQuery);

Javascript minifié

// http://stackoverflow.com/questions/2420970/how-can-i-get-selector-from-jquery-object/15623322#15623322
!function(e,t){var n=function(e){var n=[];for(;e&&e.tagName!==t;e=e.parentNode){if(e.className){var r=e.className.split(" ");for(var i in r){if(r.hasOwnProperty(i)&&r[i]){n.unshift(r[i]);n.unshift(".")}}}if(e.id&&!/\s/.test(e.id)){n.unshift(e.id);n.unshift("#")}n.unshift(e.tagName);n.unshift(" > ")}return n.slice(1).join("")};e.fn.getSelector=function(t){if(true===t){return n(this[0])}else{return e.map(this,function(e){return n(e)})}}}(window.jQuery)

Utilisation et Gotchas

<html>
    <head>...</head>
    <body>
        <div id="sidebar">
            <ul>
                <li>
                    <a href="/" id="home">Home</a>
                </li>
            </ul>
        </div>
        <div id="main">
            <h1 id="title">Welcome</h1>
        </div>

        <script type="text/javascript">

            // Simple use case
            $('#main').getSelector();           // => 'HTML > BODY > DIV#main'

            // If there are multiple matches then an array will be returned
            $('body > div').getSelector();      // => ['HTML > BODY > DIV#main', 'HTML > BODY > DIV#sidebar']

            // Passing true to the method will cause it to return the selector for the first match
            $('body > div').getSelector(true);  // => 'HTML > BODY > DIV#main'

        </script>
    </body>
</html>

Tests de violon avec QUnit

http://jsfiddle.net/CALY5/5/

Volonté
la source
J'ai aimé où vous alliez, alors j'ai apporté quelques corrections / modifications : * Le plugin jQuery tire parti de l'utilitaire jQuery $.map* délimiteur facultatif (doit supprimer les noms de balises vides étranges) * n'avez-vous pas besoin de vérifier hasOwnPropertyune foreachboucle pour être en sécurité?
drzaus
Merci pour les commentaires, je vais mettre en place une suite de tests appropriée dans un violon ce week-end et travailler sur l'incorporation de vos suggestions.
Will
1
@drzaus J'ai mis à jour la question. J'ai décidé de laisser de côté le délimiteur personnalisé que vous avez ajouté car tout délimiteur autre que le ' > 'ferait ne pas renvoyer le sélecteur d'élément.
Sera
travail sympa et agréable; Je n'avais jamais vu qunit auparavant. J'ai pensé que le délimiteur était juste pour la présentation, mais maintenant je comprends qu'il fait partie du chemin du sélecteur littéral.
drzaus
5

Avez-vous essayé cela?

 $("*").click(function(){
    $(this).attr("id"); 
 });
abhilashv
la source
3
Essayez de ne pas utiliser le *sélecteur, il est très lent!
Ben Carey
3
Cela ne fonctionne que si l'élément a un identifiant, donc pas terrible.
Glen
2

J'ai publié un plugin jQuery: jQuery Selectorator , vous pouvez obtenir un sélecteur comme celui-ci.

$("*").on("click", function(){
  alert($(this).getSelector().join("\n"));
  return false;
});
ngs
la source
C'est la seule approche qui traite des frères et sœurs clonés, merci!
Bruno Peres
2

Essaye ça:

$("*").click(function(event){
    console.log($(event.handleObj.selector));
 });
AmazingDayToday
la source
2

Ajoutez simplement une couche sur la fonction $ de cette façon:

$ = (function(jQ) { 
	return (function() { 
		var fnc = jQ.apply(this,arguments);
		fnc.selector = (arguments.length>0)?arguments[0]:null;
		return fnc; 
	});
})($);

Maintenant tu peux faire des choses comme

$ ("a"). sélecteur
et renverra "a" même sur les nouvelles versions de jQuery.

Albert Horta
la source
Cela fait exactement ce que je voulais. Cela fonctionne étrangement bien compte tenu du temps que j'ai cherché! Merci Albert.
Mark Notton
1

http://www.selectorgadget.com/ est un bookmarklet conçu explicitement pour ce cas d'utilisation.

Cela dit, je suis d'accord avec la plupart des autres personnes sur le fait que vous devriez simplement apprendre les sélecteurs CSS vous-même, essayer de les générer avec du code n'est pas durable. :)

Paul irlandais
la source
1

J'ai ajouté quelques correctifs au correctif de @ jessegavin.

Cela reviendra tout de suite s'il y a un identifiant sur l'élément. J'ai également ajouté une vérification d'attribut de nom et un sélecteur de nième enfant au cas où un élément n'aurait pas d'identifiant, de classe ou de nom.

Le nom peut nécessiter une portée au cas où il y aurait plusieurs formulaires sur la page et auraient des entrées similaires, mais je ne l'ai pas encore géré.

function getSelector(el){
    var $el = $(el);

    var id = $el.attr("id");
    if (id) { //"should" only be one of these if theres an ID
        return "#"+ id;
    }

    var selector = $el.parents()
                .map(function() { return this.tagName; })
                .get().reverse().join(" ");

    if (selector) {
        selector += " "+ $el[0].nodeName;
    }

    var classNames = $el.attr("class");
    if (classNames) {
        selector += "." + $.trim(classNames).replace(/\s/gi, ".");
    }

    var name = $el.attr('name');
    if (name) {
        selector += "[name='" + name + "']";
    }
    if (!name){
        var index = $el.index();
        if (index) {
            index = index + 1;
            selector += ":nth-child(" + index + ")";
        }
    }
    return selector;
}
Dustin
la source
1

J'obtenais plusieurs éléments même après les solutions ci-dessus, donc j'ai étendu le travail de dds1024, pour encore plus d'élément dom pointant.

par exemple DIV: nth-child (1) DIV: nth-child (3) DIV: nth-child (1) ARTICLE: nth-child (1) DIV: nth-child (1) DIV: nth-child (8) DIV : nth-child (2) DIV: nth-child (1) DIV: nth-child (2) DIV: nth-child (1) H4: nth-child (2)

Code:

function getSelector(el)
{
    var $el = jQuery(el);

    var selector = $el.parents(":not(html,body)")
                .map(function() { 
                                    var i = jQuery(this).index(); 
                                    i_str = ''; 

                                    if (typeof i != 'undefined') 
                                    {
                                        i = i + 1;
                                        i_str += ":nth-child(" + i + ")";
                                    }

                                    return this.tagName + i_str; 
                                })
                .get().reverse().join(" ");

    if (selector) {
        selector += " "+ $el[0].nodeName;
    }

    var index = $el.index();
    if (typeof index != 'undefined')  {
        index = index + 1;
        selector += ":nth-child(" + index + ")";
    }

    return selector;
}
Azghanvi
la source
1

Cela peut vous permettre de sélectionner le chemin de l'élément HTML cliqué.

 $("*").on("click", function() {

    let selectorPath = $(this).parents().map(function () {return this.tagName;}).get().reverse().join("->");

    alert(selectorPath);

    return false;

});
Vivek Kumar
la source
1

Eh bien, j'ai écrit ce simple plugin jQuery.

Cela vérifie l'identifiant ou le nom de la classe et essaie de donner autant de sélecteur exact que possible.

jQuery.fn.getSelector = function() {

    if ($(this).attr('id')) {
        return '#' + $(this).attr('id');
    }

    if ($(this).prop("tagName").toLowerCase() == 'body')    return 'body';

    var myOwn = $(this).attr('class');
    if (!myOwn) {
        myOwn = '>' + $(this).prop("tagName");
    } else {
        myOwn = '.' + myOwn.split(' ').join('.');
    }

    return $(this).parent().getSelector() + ' ' + myOwn;
}
Codemole
la source
0

Essayez-vous d'obtenir le nom du tag actuel sur lequel l'utilisateur a cliqué?

Si oui, faites ceci.

$("*").click(function(){
    alert($(this)[0].nodeName);
});

Vous ne pouvez pas vraiment obtenir le "sélecteur", le "sélecteur" dans votre cas l'est *.

Jességavin
la source
Je n'ai pas besoin du nom de la balise. J'ai juste besoin du chemin vers l'élément sur lequel j'ai cliqué.
Fidilip
1
AH, commencer à arriver quelque part "chemin vers l'élément" est très différent de "sélecteur". Alors vous avez besoin de l'élément et de tous ses noms de nœuds parents?
Mark Schultheiss
J'ai publié une autre réponse qui va plus vers votre objectif réel. Vous devez modifier la question pour qu'elle soit plus précise.
jessegavin
0

Code Javascript pour le même, au cas où quelqu'un en aurait besoin, comme j'en avais besoin. Ceci n'est que la traduction de la réponse sélectionnée ci-dessus.

    <script type="text/javascript">

function getAllParents(element){
    var a = element;
    var els = [];
    while (a && a.nodeName != "#document") {
        els.unshift(a.nodeName);
        a = a.parentNode;
    }
    return els.join(" ");
}

function getJquerySelector(element){

    var selector = getAllParents(element);
    /* if(selector){
        selector += " " + element.nodeName;
    } */
    var id = element.getAttribute("id");
    if(id){
        selector += "#" + id;
    }
    var classNames = element.getAttribute("class");
    if(classNames){
        selector += "." + classNames.replace(/^\s+|\s+$/g, '').replace(/\s/gi, ".");
    }
    console.log(selector);
    alert(selector);
    return selector;
}
</script>
jaipster
la source
0

En tenant compte de quelques réponses lues ici, j'aimerais proposer ceci:

function getSelectorFromElement($el) {
  if (!$el || !$el.length) {
    return ;
  }

  function _getChildSelector(index) {
    if (typeof index === 'undefined') {
      return '';
    }

    index = index + 1;
    return ':nth-child(' + index + ')';
  }

  function _getIdAndClassNames($el) {
    var selector = '';

    // attach id if exists
    var elId = $el.attr('id');
    if(elId){
      selector += '#' + elId;
    }

    // attach class names if exists
    var classNames = $el.attr('class');
    if(classNames){
      selector += '.' + classNames.replace(/^\s+|\s+$/g, '').replace(/\s/gi, '.');
    }

    return selector;
  }

  // get all parents siblings index and element's tag name,
  // except html and body elements
  var selector = $el.parents(':not(html,body)')
    .map(function() {
      var parentIndex = $(this).index();

      return this.tagName + _getChildSelector(parentIndex);
    })
    .get()
    .reverse()
    .join(' ');

  if (selector) {
    // get node name from the element itself
    selector += ' ' + $el[0].nodeName +
      // get child selector from element ifself
      _getChildSelector($el.index());
  }

  selector += _getIdAndClassNames($el);

  return selector;
}

Peut-être utile pour créer un plugin jQuery?

p1nox
la source
0

Merci p1nox!

Mon problème était de remettre le focus sur un appel ajax qui modifiait une partie du formulaire.

$.ajax({  url : "ajax_invite_load.php",
        async : true,
         type : 'POST',
         data : ...
     dataType : 'html',
      success : function(html, statut) {
                    var focus = $(document.activeElement).getSelector();
                    $td_left.html(html);
                    $(focus).focus();
                }
});

J'avais juste besoin d'encapsuler votre fonction dans un plugin jQuery:

    !(function ($, undefined) {

    $.fn.getSelector = function () {
      if (!this || !this.length) {
        return ;
      }

      function _getChildSelector(index) {
        if (typeof index === 'undefined') {
          return '';
        }

        index = index + 1;
        return ':nth-child(' + index + ')';
      }

      function _getIdAndClassNames($el) {
        var selector = '';

        // attach id if exists
        var elId = $el.attr('id');
        if(elId){
          selector += '#' + elId;
        }

        // attach class names if exists
        var classNames = $el.attr('class');
        if(classNames){
          selector += '.' + classNames.replace(/^\s+|\s+$/g, '').replace(/\s/gi, '.');
        }

        return selector;
      }

      // get all parents siblings index and element's tag name,
      // except html and body elements
      var selector = this.parents(':not(html,body)')
        .map(function() {
          var parentIndex = $(this).index();

          return this.tagName + _getChildSelector(parentIndex);
        })
        .get()
        .reverse()
        .join(' ');

      if (selector) {
        // get node name from the element itself
        selector += ' ' + this[0].nodeName +
          // get child selector from element ifself
          _getChildSelector(this.index());
      }

      selector += _getIdAndClassNames(this);

      return selector;
    }

})(window.jQuery);
Patrick
la source
-3

Que diriez-vous:

var selector = "*"
$(selector).click(function() {
    alert(selector);
});

Je ne crois pas que jQuery stocke le texte du sélecteur qui a été utilisé. Après tout, comment cela fonctionnerait-il si vous faisiez quelque chose comme ceci:

$("div").find("a").click(function() {
    // what would expect the 'selector' to be here?
});
Dean Harding
la source
jQuery construit en interne le sélecteur $('div').find('a').selectorest div a. Si les événements ne sont pas créés via les fonctions jQuery, mais un wrapper à la place, je pense que le sélecteur pourrait être passé en tant qu'arguments de données au gestionnaire d'événements.
Anurag
1
Est-ce vraiment une réponse sérieuse?
Glen
-5

La meilleure réponse serait

var selector = '#something';

$(selector).anything(function(){
  console.log(selector);
});
Anny
la source
4
Cela ne semble pas du tout être la meilleure réponse.
Alex