web-dev-qa-db-fra.com

Obtenez le chemin DOM du <a> cliqué

HTML

<body>
<div class="lol">
<a class="rightArrow" href="javascriptVoid:(0);" title"Next image">
</div>
</body>

Pseudo code

$(".rightArrow").click(function() {
rightArrowParents = this.dom(); //.dom(); is the pseudo function ... it should show the whole
alert(rightArrowParents);
});

Le message d'alerte serait:

corps div.lol a.rightArrow

Comment puis-je obtenir cela avec javascript/jquery?

24
Tomkay

En utilisant jQuery, comme ceci (suivi d'une solution qui n'utilise pas jQuery sauf pour l'événement; beaucoup moins d'appels de fonction, si c'est important):

$(".rightArrow").click(function() {
  var rightArrowParents = [];
  $(this).parents().addBack().not('html').each(function() {
    var entry = this.tagName.toLowerCase();
    if (this.className) {
      entry += "." + this.className.replace(/ /g, '.');
    }
    rightArrowParents.Push(entry);
  });
  alert(rightArrowParents.join(" "));
  return false;
});

Exemple en direct:

$(".rightArrow").click(function() {
  var rightArrowParents = [];
  $(this).parents().addBack().not('html').each(function() {
    var entry = this.tagName.toLowerCase();
    if (this.className) {
      entry += "." + this.className.replace(/ /g, '.');
    }
    rightArrowParents.Push(entry);
  });
  alert(rightArrowParents.join(" "));
  return false;
});
<div class="lol multi">
  <a href="#" class="rightArrow" title="Next image">Click here</a>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>

(Dans les exemples en direct, j'ai mis à jour l'attribut class sur le div pour qu'il soit lol multi pour illustrer la gestion de plusieurs classes.)

Cela utilise parents pour obtenir les ancêtres de l'élément sur lequel l'utilisateur a cliqué, enlève l'élément html de celui-ci via not = (puisque vous avez commencé à body), puis boucle en créant des entrées pour chaque parent et en les poussant sur un tableau. Ensuite, nous utilisons addBack pour ajouter le a dans l'ensemble, ce qui modifie également l'ordre de l'ensemble selon ce que vous vouliez (parents est spécial, il vous donne les parents dans l'ordre inverse de votre choix, mais ensuite addBAck le remet dans l'ordre DOM). Ensuite, il utilise Array#join pour créer la chaîne délimitée par des espaces.

Lors de la création de l'entrée, s'il y a quelque chose sur className nous remplaçons les espaces par . pour prendre en charge les éléments qui ont plus d'une classe (<p class='foo bar'> a className = "foo bar", de sorte que l'entrée finit par être p.foo.bar).

Juste pour être complet, c'est l'un de ces endroits où jQuery peut être excessif, vous pouvez facilement le faire simplement en remontant le DOM:

$(".rightArrow").click(function() {
  var rightArrowParents = [],
    Elm,
    entry;

  for (Elm = this; Elm; Elm = Elm.parentNode) {
    entry = Elm.tagName.toLowerCase();
    if (entry === "html") {
      break;
    }
    if (Elm.className) {
      entry += "." + Elm.className.replace(/ /g, '.');
    }
    rightArrowParents.Push(entry);
  }
  rightArrowParents.reverse();
  alert(rightArrowParents.join(" "));
  return false;
});

Exemple en direct:

$(".rightArrow").click(function() {
  var rightArrowParents = [],
    Elm,
    entry;

  for (Elm = this; Elm; Elm = Elm.parentNode) {
    entry = Elm.tagName.toLowerCase();
    if (entry === "html") {
      break;
    }
    if (Elm.className) {
      entry += "." + Elm.className.replace(/ /g, '.');
    }
    rightArrowParents.Push(entry);
  }
  rightArrowParents.reverse();
  alert(rightArrowParents.join(" "));
  return false;
});
<div class="lol multi">
  <a href="#" class="rightArrow" title="Next image">Click here</a>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>

Là, nous utilisons simplement la propriété standard parentNode de l'élément à plusieurs reprises pour remonter l'arborescence jusqu'à ce que nous manquions de parents ou que nous voyions l'élément html. Ensuite, nous inversons notre tableau (car il est en arrière vers la sortie que vous vouliez), et le rejoignons, et nous sommes prêts à partir.

33
T.J. Crowder

Voici une version native de JS qui renvoie un chemin jQuery. J'ajoute également des identifiants pour les éléments s'ils en ont. Cela vous donnerait la possibilité de faire le chemin le plus court si vous voyez un identifiant dans le tableau.

var path = getDomPath(element);
console.log(path.join(' > '));

Les sorties

body > section:eq(0) > div:eq(3) > section#content > section#firehose > div#firehoselist > article#firehose-46813651 > header > h2 > span#title-46813651

Voici la fonction.

function getDomPath(el) {
  var stack = [];
  while ( el.parentNode != null ) {
    console.log(el.nodeName);
    var sibCount = 0;
    var sibIndex = 0;
    for ( var i = 0; i < el.parentNode.childNodes.length; i++ ) {
      var sib = el.parentNode.childNodes[i];
      if ( sib.nodeName == el.nodeName ) {
        if ( sib === el ) {
          sibIndex = sibCount;
        }
        sibCount++;
      }
    }
    if ( el.hasAttribute('id') && el.id != '' ) {
      stack.unshift(el.nodeName.toLowerCase() + '#' + el.id);
    } else if ( sibCount > 1 ) {
      stack.unshift(el.nodeName.toLowerCase() + ':eq(' + sibIndex + ')');
    } else {
      stack.unshift(el.nodeName.toLowerCase());
    }
    el = el.parentNode;
  }

  return stack.slice(1); // removes the html element
}
40
Michael Connor

J'avais besoin d'une version native de JS, qui renvoie le chemin d'accès standard CSS (pas jQuery) et traite de ShadowDOM. Ce code est une mise à jour mineure de la réponse de Michael Connor, juste au cas où quelqu'un d'autre en aurait besoin:

function getDomPath(el) {
  if (!el) {
    return;
  }
  var stack = [];
  var isShadow = false;
  while (el.parentNode != null) {
    // console.log(el.nodeName);
    var sibCount = 0;
    var sibIndex = 0;
    // get sibling indexes
    for ( var i = 0; i < el.parentNode.childNodes.length; i++ ) {
      var sib = el.parentNode.childNodes[i];
      if ( sib.nodeName == el.nodeName ) {
        if ( sib === el ) {
          sibIndex = sibCount;
        }
        sibCount++;
      }
    }
    // if ( el.hasAttribute('id') && el.id != '' ) { no id shortcuts, ids are not unique in shadowDom
    //   stack.unshift(el.nodeName.toLowerCase() + '#' + el.id);
    // } else
    var nodeName = el.nodeName.toLowerCase();
    if (isShadow) {
      nodeName += "::shadow";
      isShadow = false;
    }
    if ( sibCount > 1 ) {
      stack.unshift(nodeName + ':nth-of-type(' + (sibIndex + 1) + ')');
    } else {
      stack.unshift(nodeName);
    }
    el = el.parentNode;
    if (el.nodeType === 11) { // for shadow dom, we
      isShadow = true;
      el = el.Host;
    }
  }
  stack.splice(0,1); // removes the html element
  return stack.join(' > ');
}
10
Aleksandar Totic

Voici une solution pour la correspondance exacte d'un élément.

Il est important de comprendre que le sélecteur ( ce n'est pas un vrai ) que les outils chrome affichent n'identifient pas de façon unique un élément dans le DOM. ( par exemple, il ne fera pas la distinction entre une liste de span éléments. il n'y a pas d'informations de positionnement/d'indexation )

Une adaptation d'une similaire ( à propos de xpath ) réponse

$.fn.fullSelector = function () {
    var path = this.parents().addBack();
    var quickCss = path.get().map(function (item) {
        var self = $(item),
            id = item.id ? '#' + item.id : '',
            clss = item.classList.length ? item.classList.toString().split(' ').map(function (c) {
                return '.' + c;
            }).join('') : '',
            name = item.nodeName.toLowerCase(),
            index = self.siblings(name).length ? ':nth-child(' + (self.index() + 1) + ')' : '';

        if (name === 'html' || name === 'body') {
            return name;
        }
        return name + index + id + clss;

    }).join(' > ');

    return quickCss;
};

Et tu peux l'utiliser comme ça

console.log( $('some-selector').fullSelector() );

Démo sur http://jsfiddle.net/gaby/zhnr198y/

3
Gabriele Petrioli

J'ai déplacé l'extrait de T.J. Crowder à un petit plugin jQuery. J'ai utilisé la version jQuery de lui même s'il a raison de dire que c'est une surcharge totalement inutile, mais je ne l'utilise qu'à des fins de débogage, donc je m'en fiche.

Usage:

Html

<html>
<body>
    <!-- Two spans, the first will be chosen -->
    <div>
        <span>Nested span</span>
    </div>
    <span>Simple span</span>

    <!-- Pre element -->
    <pre>Pre</pre>
</body>
</html>

Javascript

// result (array): ["body", "div.sampleClass"]
$('span').getDomPath(false)

// result (string): body > div.sampleClass
$('span').getDomPath()

// result (array): ["body", "div#test"]
$('pre').getDomPath(false)

// result (string): body > div#test
$('pre').getDomPath()

Référentiel

https://bitbucket.org/tehrengruber/jquery.dom.path

2
darthmatch
$(".rightArrow")
  .parents()
  .map(function () { 
      var value = this.tagName.toLowerCase();
      if (this.className) {
          value += '.' + this.className.replace(' ', '.', 'g');
      }
      return value;
  })
  .get().reverse().join(", ");
0
sv_in

bonjour cette fonction résout le bogue lié à l'élément courant qui n'apparaît pas dans le chemin

vérifie ça maintenant

$j(".wrapper").click(function(event) {
      selectedElement=$j(event.target);

      var rightArrowParents = [];
      $j(event.target).parents().not('html,body').each(function() {
          var entry = this.tagName.toLowerCase();
          if (this.className) {
              entry += "." + this.className.replace(/ /g, '.');
          }else if(this.id){
              entry += "#" + this.id;
          }
          entry=replaceAll(entry,'..','.');
          rightArrowParents.Push(entry);
      });
      rightArrowParents.reverse();
      //if(event.target.nodeName.toLowerCase()=="a" || event.target.nodeName.toLowerCase()=="h1"){
        var entry = event.target.nodeName.toLowerCase();
        if (event.target.className) {
              entry += "." + event.target.className.replace(/ /g, '.');
        }else if(event.target.id){
              entry += "#" + event.target.id;
        }
        rightArrowParents.Push(entry);
     // }

$j = variable jQuery

résolvez également le problème avec .. dans le nom de la classe

voici la fonction de remplacement:

function escapeRegExp(str) {
    return str.replace(/([.*+?^=!:${}()|\[\]\/\\])/g, "\\$1");
}
  function replaceAll(str, find, replace) {
  return str.replace(new RegExp(escapeRegExp(find), 'g'), replace);
}

Merci

0
Jayram Prajapati
    var obj = $('#show-editor-button'),
       path = '';
    while (typeof obj.prop('tagName') != "undefined"){
        if (obj.attr('class')){
            path = '.'+obj.attr('class').replace(/\s/g , ".") + path;
        }
        if (obj.attr('id')){
            path = '#'+obj.attr('id') + path;
        }
        path = ' ' +obj.prop('tagName').toLowerCase() + path;
        obj = obj.parent();
    }
    console.log(path);
0
Haradzieniec