IT이야기

Jquery에서 고유한 요소 선택기 가져오기

cyworld 2021. 10. 16. 10:41
반응형

Jquery에서 고유한 요소 선택기 가져오기


나는 사용자의 모든 행동을 추적하는 레코더와 같은 것을 만들고 싶습니다. 이를 위해서는 사용자가 상호 작용하는 요소를 식별해야 나중에 세션에서 이러한 요소를 참조할 수 있습니다.

의사 코드로 말하면 다음과 같은 것을 할 수 있기를 원합니다.

샘플 HTML(복잡할 수 있음):

<html>
<body>
  <div class="example">
    <p>foo</p>
    <span><a href="bar">bar</a></span>
  </div>
</body>
</html>

사용자가 링크와 같은 항목을 클릭합니다. 이제 클릭한 요소를 식별하고 나중에 사용할 수 있도록 DOM 트리에 위치를 저장해야 합니다.

(any element).onclick(function() {
  uniqueSelector = $(this).getUniqueSelector();
})

이제 uniqueSelector는 다음과 같아야 합니다(xpath 또는 css 선택기 스타일인 경우 상관 없음).

html > body > div.example > span > a

이렇게 하면 해당 선택기 문자열을 저장하고 나중에 사용자가 수행한 작업을 재생하는 데 사용할 수 있습니다.

어떻게 그게 가능합니까?

업데이트

내 대답을 얻었습니다 : 요소에 대한 jQuery 선택기 얻기


수정해야 하는 솔루션을 찾았기 때문에 직접 답변하겠습니다. 다음 스크립트가 작동 중이며 Blixt스크립트를 기반으로 합니다 .

jQuery.fn.extend({
    getPath: function () {
        var path, node = this;
        while (node.length) {
            var realNode = node[0], name = realNode.localName;
            if (!name) break;
            name = name.toLowerCase();

            var parent = node.parent();

            var sameTagSiblings = parent.children(name);
            if (sameTagSiblings.length > 1) { 
                var allSiblings = parent.children();
                var index = allSiblings.index(realNode) + 1;
                if (index > 1) {
                    name += ':nth-child(' + index + ')';
                }
            }

            path = name + (path ? '>' + path : '');
            node = parent;
        }

        return path;
    }
});

@Alp의 것과 동일한 솔루션이지만 여러 jQuery 요소와 호환됩니다.

jQuery('.some-selector')하나 이상의 DOM 요소가 발생할 수 있습니다. @Alp의 솔루션은 불행히도 첫 번째 솔루션에서만 작동합니다. 내 솔루션은 모든 항목을 ,.

첫 번째 요소만 처리하려면 다음과 같이 하십시오.

jQuery('.some-selector').first().getPath();

// or
jQuery('.some-selector:first').getPath();

개선된 버전

jQuery.fn.extend({
    getPath: function() {
        var pathes = [];

        this.each(function(index, element) {
            var path, $node = jQuery(element);

            while ($node.length) {
                var realNode = $node.get(0), name = realNode.localName;
                if (!name) { break; }

                name = name.toLowerCase();
                var parent = $node.parent();
                var sameTagSiblings = parent.children(name);

                if (sameTagSiblings.length > 1)
                {
                    var allSiblings = parent.children();
                    var index = allSiblings.index(realNode) + 1;
                    if (index > 0) {
                        name += ':nth-child(' + index + ')';
                    }
                }

                path = name + (path ? ' > ' + path : '');
                $node = parent;
            }

            pathes.push(path);
        });

        return pathes.join(',');
    }
});

(any element).onclick(function() {
  uniqueSelector = $(this).getUniqueSelector();
})

this IS 고유 선택자 및 클릭한 요소에 대한 경로입니다. 왜 그것을 사용하지 않습니까? jquery의 $.data()방법을 활용 하여 jquery 선택기를 설정할 수 있습니다 . 또는 앞으로 사용해야 하는 요소를 푸시하면 됩니다.

var elements = [];
(any element).onclick(function() {
  elements.push(this);
})

xpath가 정말로 필요한 경우 다음 코드를 사용하여 계산할 수 있습니다.

  function getXPath(node, path) {
    path = path || [];
    if(node.parentNode) {
      path = getXPath(node.parentNode, path);
    }

    if(node.previousSibling) {
      var count = 1;
      var sibling = node.previousSibling
      do {
        if(sibling.nodeType == 1 && sibling.nodeName == node.nodeName) {count++;}
        sibling = sibling.previousSibling;
      } while(sibling);
      if(count == 1) {count = null;}
    } else if(node.nextSibling) {
      var sibling = node.nextSibling;
      do {
        if(sibling.nodeType == 1 && sibling.nodeName == node.nodeName) {
          var count = 1;
          sibling = null;
        } else {
          var count = null;
          sibling = sibling.previousSibling;
        }
      } while(sibling);
    }

    if(node.nodeType == 1) {
      path.push(node.nodeName.toLowerCase() + (node.id ? "[@id='"+node.id+"']" : count > 0 ? "["+count+"]" : ''));
    }
    return path;
  };

참조: http://snippets.dzone.com/posts/show/4349


더 나은 솔루션은 임의의 ID를 생성한 다음 해당 ID를 기반으로 요소에 액세스하는 것입니다.

고유 ID 할당:

// or some other id-generating algorithm
$(this).attr('id', new Date().getTime()); 

고유 ID를 기반으로 선택:

// getting unique id
var uniqueId = $(this).getUniqueId();

// or you could just get the id:
var uniqueId = $(this).attr('id');

// selecting by id:
var element = $('#' + uniqueId);

// if you decide to use another attribute other than id:
var element = $('[data-unique-id="' + uniqueId + '"]');

질문은 jQuery에 대한 것이지만 ES6에서는 Vanilla JavaScript용 @Alp와 유사한 것을 얻는 것이 매우 쉽습니다( nameCount사용을 최소화하기 위해 추적하는 몇 줄도 추가했습니다 nth-child).

function getSelectorForElement (elem) {
    let path;
    while (elem) {
        let subSelector = elem.localName;
        if (!subSelector) {
            break;
        }
        subSelector = subSelector.toLowerCase();

        const parent = elem.parentElement;

        if (parent) {
            const sameTagSiblings = parent.children;
            if (sameTagSiblings.length > 1) {
                let nameCount = 0;
                const index = [...sameTagSiblings].findIndex((child) => {
                    if (elem.localName === child.localName) {
                        nameCount++;
                    }
                    return child === elem;
                }) + 1;
                if (index > 1 && nameCount > 1) {
                    subSelector += ':nth-child(' + index + ')';
                }
            }
        }

        path = subSelector + (path ? '>' + path : '');
        elem = parent;
    }
    return path;
}

순수 자바스크립트 솔루션

참고: 이것은 Array.fromArray.prototype.filter를 사용합니다 . 둘 다 IE11에서 폴리필해야 합니다.

function getUniqueSelector(node) {
  let selector = "";
  while (node.parentElement) {
    const siblings = Array.from(node.parentElement.children).filter(
      e => e.tagName === node.tagName
    );
    selector =
      (siblings.indexOf(node)
        ? `${node.tagName}:nth-of-type(${siblings.indexOf(node) + 1})`
        : `${node.tagName}`) + `${selector ? " > " : ""}${selector}`;
    node = node.parentElement;
  }
  return `html > ${selector.toLowerCase()}`;
}

용법

getUniqueSelector(document.getElementsByClassName('SectionFour')[0]);

getUniqueSelector(document.getElementById('content'));

이 답변은 원래 질문 설명을 충족하지 않지만 제목 질문에 대한 답변입니다. 요소에 대한 고유 선택기를 얻는 방법을 찾고 있는 이 질문에 왔지만 선택기가 페이지 로드 간에 유효할 필요가 없었습니다. 따라서 내 대답은 페이지 로드 간에 작동하지 않습니다.

DOM을 수정하는 것은 이상적이지는 않지만 코드 한 톨 없이 고유한 선택기를 만드는 좋은 방법이라고 생각합니다. @Eli의 답변을 읽은 후이 아이디어를 얻었습니다.

고유한 값으로 사용자 정의 속성을 할당하십시오.

$(element).attr('secondary_id', new Date().getTime())
var secondary_id = $(element).attr('secondary_id');

그런 다음 해당 고유 ID를 사용하여 CSS 선택기를 빌드합니다.

var selector = '[secondary_id='+secondary_id+']';

그런 다음 요소를 선택하는 선택기가 있습니다.

var found_again = $(selector);

그리고 많은 사람들이 secondary_id요소에 이미 속성 이 없는지 확인하고 싶어합니다 .

if ($(element).attr('secondary_id')) {
  $(element).attr('secondary_id', (new Date()).getTime());
}
var secondary_id = $(element).attr('secondary_id');

함께 모아서

$.fn.getSelector = function(){
  var e = $(this);

  // the `id` attribute *should* be unique.
  if (e.attr('id')) { return '#'+e.attr('id') }

  if (e.attr('secondary_id')) {
    return '[secondary_id='+e.attr('secondary_id')+']'
  }

  $(element).attr('secondary_id', (new Date()).getTime());

  return '[secondary_id='+e.attr('secondary_id')+']'
};

var selector = $('*').first().getSelector();

ID 속성(예: id="something")이 있는 경우 다음과 같은 값을 가져와야 합니다.

var selector = "[id='" + $(yourObject).attr("id") + "']";
console.log(selector); //=> [id='something']
console.log($(selector).length); //=> 1

ID 속성이 없고 선택기를 가져오려는 경우 ID 속성을 만들 수 있습니다. 위와 같은 내용,

var uuid = guid();
$(yourObject).attr("id", uuid); // Set the uuid as id of your object.

당신은 당신의 자신의 GUID 방법을 사용하거나에있는 소스 코드를 사용할 수 있습니다 , 대답 있도록

function guid() {
    function s4() {
        return Math.floor((1 + Math.random()) * 0x10000)
                .toString(16)
                .substring(1);
    }
    return s4() + s4() + '-' + s4() + '-' + s4() + '-' +
            s4() + '-' + s4() + s4() + s4();
}

findCssSelector 도 살펴볼 수 있습니다 . 코드는 내 다른 답변에 있습니다.


나는 내 자신을 위해 수정 된 솔루션을 찾았습니다. 경로 선택기 #id, .className에 추가하고 #id에 대한 경로 길이를 자릅니다.

$.fn.extend({
            getSelectorPath: function () {
                var path,
                    node = this,
                    realNode,
                    name,
                    parent,
                    index,
                    sameTagSiblings,
                    allSiblings,
                    className,
                    classSelector,
                    nestingLevel = true;

                while (node.length && nestingLevel) {
                    realNode = node[0];
                    name = realNode.localName;

                    if (!name) break;

                    name = name.toLowerCase();
                    parent = node.parent();
                    sameTagSiblings = parent.children(name);

                    if (realNode.id) {
                        name += "#" + node[0].id;

                        nestingLevel = false;

                    } else if (realNode.className.length) {
                        className =  realNode.className.split(' ');
                        classSelector = '';

                        className.forEach(function (item) {
                            classSelector += '.' + item;
                        });

                        name += classSelector;

                    } else if (sameTagSiblings.length > 1) {
                        allSiblings = parent.children();
                        index = allSiblings.index(realNode) + 1;

                        if (index > 1) {
                            name += ':nth-child(' + index + ')';
                        }
                    }

                    path = name + (path ? '>' + path : '');
                    node = parent;
                }

                return path;
            }
        });


다음과 같이 할 수 있습니다.

$(".track").click(function() {
  recordEvent($(this).attr("id"));
});

클래스 onclick가 있는 모든 객체에 이벤트 핸들러를 연결합니다 track. 개체를 클릭할 때마다 개체의 ID가 recordEvent()함수에 입력됩니다 . 이 함수가 각 개체의 시간과 ID 또는 원하는 것을 기록하도록 할 수 있습니다.


$(document).ready(function() {
    $("*").click(function(e) {
        var path = [];
        $.each($(this).parents(), function(index, value) {
            var id = $(value).attr("id");
            var class = $(value).attr("class");
            var element = $(value).get(0).tagName
                path.push(element + (id.length > 0 ? " #" + id : (class.length > 0 ? " .": "") + class));
        });
        console.log(path.reverse().join(">"));
        return false;
    });
});

작업 예: http://jsfiddle.net/peeter/YRmr5/

* 선택기(매우 느림)를 사용하고 이벤트 버블링을 중지할 때 문제가 발생할 수 있지만 더 많은 HTML 코드 없이는 실제로 도움이 되지 않습니다.


당신은 그런 일을 할 수 있습니다 (테스트되지 않음)

function GetPathToElement(jElem)
{
   var tmpParent = jElem;
   var result = '';
   while(tmpParent != null)
   {
       var tagName = tmpParent.get().tagName;
       var className = tmpParent.get().className;
       var id = tmpParent.get().id;
       if( id != '') result = '#' + id + result;
       if( className !='') result = '.' + className + result;
       result = '>' + tagName + result;
       tmpParent = tmpParent.parent();
    }
    return result;
}

이 기능은 요소에 대한 "경로"를 저장합니다. 이제 나중에 요소를 다시 찾기 위해 html과 같은 방식으로 거의 불가능할 것입니다. 이 기능에서는 각 요소의 형제 인덱스를 저장하지 않고 저장만 하기 때문입니다. ID 및 클래스.

따라서 html 문서의 모든 요소에 ID가 없으면 이 접근 방식은 작동하지 않습니다.

ReferenceURL : https://stackoverflow.com/questions/5706837/get-unique-selector-of-element-in-jquery

반응형