是否存在反向querySelector?

时间:2014-01-09 16:58:43

标签: javascript firefox dom

我知道我可以使用querySelector来定位文档中的元素

var element = document.querySelector(".myclass")

但是是否存在反向querySelector:

var selector = document.inverseQuerySelector(element);
Assert.AreEqual(element, document.querySelector(selector));

inverseQuerySelector的返回选择器总是唯一标识指定的元素吗?

3 个答案:

答案 0 :(得分:2)

不,因为有很多选择器(可能是无限的)可以选择相同的元素。

对于一个可逆的函数(即使在数学中),它的映射必须是1到1,但事实并非如此。

BTW,因此,您可以创建一些仅在某些情况下 的作品。例如:

function inverseForElementWithUniqueId(element){
   return '#' + element.id;
}

var selector = inverseForElementWithUniqueId(element);
Assert.AreEqual(element, document.querySelector(selector));   //True

(代码确实可能看起来微不足道)

但正如所说,由于这个理论,这只适用于一部分案例。

但是,它有时只会起作用

答案 1 :(得分:1)

您可以创建一个适用于所有情况的。有两种方式:

  1. 使用 nth-child (使用索引)
  2. 解决方案如下:

    function getMyPathByIndex(element){
    
            if(element == null)
                return '';
    
            if(element.parentElement == null)
                return 'html'
    
            return getMyPathByIndex(element.parentElement) + '>' + ':nth-child(' + getMyIndex(element) + ')';
    
        }
    
    function getMyIndex(element){
    
            if(element == null)
                return -1;
            if(element.parentElement == null)
                return 0;
    
            let parent = element.parentElement;
    
            for(var index = 0; index < parent.childElementCount; index++)
                if(parent.children[index] == element)
                    return index + 1;
    
    }
    

    例如,元素

    <a id="y" class="vote-up-off" title="This answer is useful">up vote</a> 
    

    只需在控制台中输入

    ,即可在此页面中获取此元素
    document.querySelector('a[title="This answer is useful"]');
    

    唯一的querySelector

      

    HTML&GT;:第n个孩子(2)&GT;:第n个孩子(5)&GT;:第n个孩子(1)&GT;:第n个孩子(1)&GT;:第n个孩子(3)&GT; :第n个孩子(2)&GT;:第n个孩子(6)&GT;:第n个孩子(1)&GT;:第n个孩子(1)&GT;:第n个孩子(1)&GT;:第n个孩子( 1)&GT;:第n个孩子(1)&GT;:第n个孩子(2)

    1. 属性用于“人类可读”的方式
      1. 获取元素的属性(仅显式属性)。
      2. 获取元素的完整路径。
      3. 使用多属性选择器统一所有功能。
    2. 之前使用相同的元素唯一的querySelector

        

      HTML&GT;主体&GT; DIV&GT; DIV&GT; DIV&GT; DIV&GT; DIV&GT; DIV&GT;表&gt; TBODY&GT; TR&GT; TD&GT; DIV&gt;一种[ID = “Y”] [类= “投票向上客”] [标题=“此   答案很有用“]

      测试解决方案是否正确

      // e is an element and e must exist inside the page
      document.querySelector( getMyPathByIndex(e)) === e && 
      document.querySelectorAll( getMyPathByIndex(e)).length === 1
      

      代码解决方案如下:

      function convertAttributesToQuerySelector(element){
      
        var tagName = element.tagName.toLowerCase();
        var result = tagName;   
      
        Array.prototype.slice.call(element.attributes).forEach( function(item) {
        if(element.outerHTML.contains(item.name))
          result += '[' + item.name +'="' + item.value + '"]';
      
      });
      
        return result;
        //["a[id="y"]", "a[class="vote-up-off"]", "a[title="This answer is useful"]"]
      
      }
      
      function getMyPath(element){
      
         if(element.parentElement.tagName == 'HTML')
          return 'html';
      
        return  getMyPath(element.parentElement) + '>' + element.parentElement.tagName.toLowerCase() ;
        //"html>body>div>div>div>div>div>div>table>tbody>tr>td>div"
      
      }
      
      function myUniqueQuerySelector(element){
      
        var elementPath = getMyPath(element);
        var simpleSelector =   convertAttributesToQuerySelector(element);
      
        return elementPath + '>' + simpleSelector;
      
      }
      

      您可以随时测试解决方案是否正确

      // e is an element and e must exist inside the page
      document.querySelector( myUniqueQuerySelector(e)) === e && 
      document.querySelectorAll( myUniqueQuerySelector(e)).length === 1
      

答案 2 :(得分:0)

我混合了提出的 2 个解决方案,以获得人类可读的结果,如果有几个类似的兄弟姐妹,它会给出正确的元素:

function elemToSelector(elem) {
  const {
    tagName,
    id,
    className,
    parentNode
  } = elem;

  if (tagName === 'HTML') return 'HTML';

  let str = tagName;

  str += (id !== '') ? `#${id}` : '';

  if (className) {
    const classes = className.split(/\s/);
    for (let i = 0; i < classes.length; i++) {
      str += `.${classes[i]}`;
    }
  }

  let childIndex = 1;

  for (let e = elem; e.previousElementSibling; e = e.previousElementSibling) {
    childIndex += 1;
  }

  str += `:nth-child(${childIndex})`;

  return `${elemToSelector(parentNode)} > ${str}`;
}

测试:

// Select an element in Elements tab of your navigator Devtools, or replace $0

document.querySelector(elemToSelector($0)) === $0 &&
document.querySelectorAll(elemToSelector($0)).length === 1

这可能会给你一些类似的东西,它有点长,但它是可读的,而且总是有效:

HTML > BODY:nth-child(2) > DIV.container:nth-child(2) > DIV.row:nth-child(2) > DIV.col-md-4:nth-child(2) > DIV.sidebar:nth-child(1) > DIV.sidebar-wrapper:nth-child(2) > DIV.my-4:nth-child(1) > H4:nth-child(3)

编辑:我刚刚找到包 unique-selector