web-dev-qa-db-ja.com

クリックされた<a>のDOMパスを取得する

HTML

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

疑似コード

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

警告メッセージは次のようになります。

body div.lol a.rightArrow

Javascript/jqueryでこれを取得するにはどうすればよいですか?

24
Tomkay

次のようなjQueryを使用します(イベント以外はjQueryを使用しないソリューションが続きます。それが重要な場合は、関数呼び出しが大幅に少なくなります)。

$(".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;
});

実際の例:

$(".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>

(実際の例では、複数のクラスの処理を示すために、classdiv属性をlol multiに更新しました。)

parents を使用して、クリックされた要素の祖先を取得し、_ html を介してnot要素を削除します=(bodyから開始したため)、ループして各親のエントリを作成し、配列にプッシュします。次に addBack を使用してaをセットに戻します。これにより、セットの順序も希望どおりに変更されます(parents is特別なことですが、親に希望する順序とは逆の順序で与えますが、addBAckはDOM順序に戻します)。次に、Array#joinを使用してスペース区切りの文字列を作成します。

エントリを作成するとき、classNameに何かがある場合は、スペースを.に置き換えて、複数のクラスを持つ要素をサポートします(<p class='foo bar'>className = "foo bar"なので、エントリは最終的にp.foo.bar)になります。

完全を期すために、これはjQueryがやり過ぎである可能性がある場所の1つであり、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;
});

実際の例:

$(".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>

そこでは、要素の標準 parentNode property を繰り返し使用して、親がなくなるか、html要素が見つかるまで、ツリーを上に向かって歩いていきます。次に、配列を反転し(必要な出力に逆向きになっているため)、結合します。

33
T.J. Crowder

以下は、jQueryパスを返すネイティブJSバージョンです。要素のIDがある場合は、それらも追加します。これにより、配列にIDが表示された場合に最短パスを実行する機会が与えられます。

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

アウトプット

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

これが関数です。

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

CSSの標準パス(jQueryではなく)を返し、ShadowDOMを処理するネイティブJSバージョンが必要でした。このコードは、誰か他の人がそれを必要とする場合に備えて、Michael Connorの回答のマイナーアップデートです。

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

要素を正確に一致させるためのソリューションを次に示します。

selectorそれは実際のものではないことを理解することが重要です)chrome toolsは、DOM内の要素を一意に識別しません。(たとえば、連続するspan elements。位置付け/インデックス付け情報はありません

similar(about xpath)回答からの適応

$.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;
};

そして、あなたはこのようにそれを使うことができます

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

でのデモhttp://jsfiddle.net/gaby/zhnr198y/

3

T.Jからスニペットを移動しました。小さなjQueryプラグインのクラウダー。私は彼のjQueryバージョンを使用しましたが、これは完全に不要なオーバーヘッドであると彼が言っているのは正しいですが、私はデバッグ目的でのみ使用するので気にしません。

使用法:

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

リポジトリ

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

こんにちはこの関数は、パスに表示されない現在の要素に関連するバグを解決します

今これをチェック

$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 = jQuery変数

クラス名の..の問題も解決します

ここに置換機能があります:

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

ありがとう

0
    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