【问题标题】:pure Javascript get parents纯Javascript获取父母
【发布时间】:2019-06-14 11:47:18
【问题描述】:

我基于.parents() without jquery - or querySelectorAll for parents创建了一个sn-p

  function getParents (el, _class) {
    let doc = document
    let parents = []
    let p = el.parentNode

    while (p !== doc) {
      let o = p
      parents.push(o)
      p = o.parentNode
    }
    parents.push(doc)
    return parents[parents.map(x => x.className).indexOf(_class)]
  }

document.querySelectorAll('.child1').forEach((e,i)=>{
  console.log(getParents(e, 'child4'))
})
<div class="parent">
  <div class="child5">
    <div class="child4">
      <div class="child3">
        <div class="child2">
          <div class="child1">
            1
          </div>
        </div>
      </div>
    </div>
  </div>
</div>


  <div class="parent">
  <div class="child5">
    <div class="child4">
      <div class="child3">
        <div class="child2">
          <div class="child1">
            2
          </div>
        </div>
      </div>
    </div>
  </div>
</div>


  <div class="parent">
  <div class="child5">
    <div class="child4 hello">  <!-- problem here -->
      <div class="child3">
        <div class="child2">
          <div class="child1">
            3
          </div>
        </div>
      </div>
    </div>
  </div>
</div>

如果&lt;div class="child4 hello"&gt; 没有hello 我可以获得所有child4,如果添加hello 或其他任何内容,我将无法获得child4。我使用indexOf() 我认为不应该是-1 或未定义。有人可以纠正我错误在哪里吗?谢谢

【问题讨论】:

    标签: javascript


    【解决方案1】:

    问题是你得到了一个元素列表并且你将它们映射到元素的className,当目标元素有更多而不是child4类时,数组中的值将是child4 hello 并且当您在数组中查找 child4 值的索引时,child4 hello 将不匹配。你可以使用Array.find,而不是Array.indexOf

      function getParents (el, _class) {
        let doc = document
        let parents = []
        let p = el.parentNode
    
        while (p !== doc) {
          let o = p
          parents.push(o)
          p = o.parentNode
        }
        parents.push(doc)
        return parents.find(e => e.className.includes(_class))
      }
    
    document.querySelectorAll('.child1').forEach((e,i)=>{
      console.log(getParents(e, 'child4'))
    })
    <div class="parent">
      <div class="child5">
        <div class="child4">
          <div class="child3">
            <div class="child2">
              <div class="child1">
                1
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>
    
    
      <div class="parent">
      <div class="child5">
        <div class="child4">
          <div class="child3">
            <div class="child2">
              <div class="child1">
                2
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>
    
    
      <div class="parent">
      <div class="child5">
        <div class="child4 hello">  <!-- problem here -->
          <div class="child3">
            <div class="child2">
              <div class="child1">
                3
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>

    你可以使用Element.closest代替getParents函数

    这是一个例子:

    const parents = Array.from(document.querySelectorAll('.child1')).map(e => e.closest('.child4'));
    console.log(parents);
    <div class="parent">
      <div class="child5">
        <div class="child4">
          <div class="child3">
            <div class="child2">
              <div class="child1">
                1
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>
    
    
    <div class="parent">
      <div class="child5">
        <div class="child4">
          <div class="child3">
            <div class="child2">
              <div class="child1">
                2
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>
    
    
    <div class="parent">
      <div class="child5">
        <div class="child4 hello">
          <!-- problem here -->
          <div class="child3">
            <div class="child2">
              <div class="child1">
                3
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>

    正如@Khauri 提到的,在第一个示例中,与其使用className 属性并使用字符串函数来检查该值是否匹配,不如使用classList 属性,因为它有一个@ 987654337@函数。

    【讨论】:

    • classList.contains 在这里更好。 className.includes 将在搜索包含子字符串而不是特定类的类名时返回 true。例如 child4 中的“child”
    【解决方案2】:

    问题在于,当您执行parents.map(x =&gt; x.className) 时,您将获得一个包含每个元素的完整类字符串的数组。所以结果看起来像(简化的)[ "child4 hello" ],你尝试在那个 array 上做indexOf("child4")。由于没有简单的"child4" 成员,因此失败。

    这里是有问题的代码:

    function getParents (el, _class) {
        let doc = document
        let parents = []
        let p = el.parentNode
    
        while (p !== doc) {
          let o = p
          parents.push(o)
          p = o.parentNode
        }
        parents.push(doc)
        let mappedClassName = parents.map(x => x.className)
        console.log("mappedClassName", mappedClassName)
        let indexOf = mappedClassName.indexOf(_class);
        console.log("indexOf", indexOf)
        return parents[indexOf]
      }
    
    document.querySelectorAll('.child1').forEach((e,i)=>{
      console.log(getParents(e, 'child4'))
    })
    <div class="parent">
      <div class="child5">
        <div class="child4 hello">  <!-- problem here -->
          <div class="child3">
            <div class="child2">
              <div class="child1">
                3
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>

    这段代码可以使用字符串

    let indexOf = "child4 hello".indexOf("child4");
    console.log(indexOf);

    但是,它不一定能正常工作

    //the class is NOT child4
    let indexOf = "child42 hello".indexOf("child4");
    console.log(indexOf);

    您应该使用Element.classList 进行更准确的类检查:

    let div1 = document.getElementById("one");
    let div2 = document.getElementById("two");
    
    let _class = "child4";
    console.log(`div1 has ${_class}`, div1.classList.contains(_class))
    console.log(`div2 has ${_class}`, div2.classList.contains(_class))
    <div id="one" class="child4 hello"></div>
    <div id="two" class="child42 hello"></div>

    如果你将它与Array#findIndex 结合来实现你想要的:

    function getParents (el, _class) {
        let doc = document
        let parents = []
        let p = el.parentNode
    
        while (p !== doc) {
          let o = p
          parents.push(o)
          p = o.parentNode
        }
        parents.push(doc)
        return parents[parents.map(x => x.classList).findIndex(cl => cl.contains(_class))]
        //                                ^^^^^^^^^  ^^^^^^^^^
      }
    
    document.querySelectorAll('.child1').forEach((e,i)=>{
      console.log(getParents(e, 'child4'))
    })
    <div class="parent">
      <div class="child5">
        <div class="child4">
          <div class="child3">
            <div class="child2">
              <div class="child1">
                1
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>
    
    
      <div class="parent">
      <div class="child5">
        <div class="child4">
          <div class="child3">
            <div class="child2">
              <div class="child1">
                2
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>
    
    
      <div class="parent">
      <div class="child5">
        <div class="child4 hello">  <!-- problem here -->
          <div class="child3">
            <div class="child2">
              <div class="child1">
                3
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>

    您可以通过删除.map 并在.findIndex 中运行逻辑来稍微缩短代码:

    parents.findIndex(x => x.classList.contains(_class))
    

    然而,话虽如此,您的算法只检查。您可以使用Element.matches 轻松扩展它以使用任何选择器:

    function getParents (el, selector) {
        let doc = document
        let parents = []
        let p = el.parentNode
    
        while (p !== doc) {
          let o = p
          parents.push(o)
          p = o.parentNode
        }
        parents.push(doc)
        return parents[parents.findIndex(x => x instanceof Element && x.matches(selector))]
        // only check Elements -------------> ^^^^^^^^^^^^^^^^^^^^              
      }
    
    document.querySelectorAll('.child1').forEach((e,i)=>{
      console.log('.child4', getParents(e, '.child4'))
    })
    
    
    document.querySelectorAll('.child1').forEach((e,i)=>{
      console.log('#parentTwo.child4', getParents(e, '#parentTwo.child4'))
    })
    <div class="parent">
      <div class="child5">
        <div id="parentOne" class="child4">
          <div class="child3">
            <div class="child2">
              <div class="child1">
                1
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>
    
    
      <div class="parent">
      <div class="child5">
        <div id="parentTwo" class="child4">
          <div class="child3">
            <div class="child2">
              <div class="child1">
                2
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>
    
    
      <div class="parent">
      <div class="child5">
        <div id="parentThree" class="child4 hello">
          <div class="child3">
            <div class="child2">
              <div class="child1">
                3
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>

    【讨论】:

      【解决方案3】:

      您可以像这样使用数组原型的findIndexreturn parents[parents.map(x =&gt; x.className).findIndex(x =&gt; x.indexOf(_class) &gt; -1)]

      function getParents (el, _class) {
          let doc = document
          let parents = []
          let p = el.parentNode
      
          while (p !== doc) {
            let o = p
            parents.push(o)
            p = o.parentNode
          }
          parents.push(doc)
          return parents[parents.map(x => x.className).findIndex(x => x.indexOf(_class) > -1)]
        }
      
      document.querySelectorAll('.child1').forEach((e,i)=>{
        console.log(getParents(e, 'child4'))
      })
      <div class="parent">
        <div class="child5">
          <div class="child4">
            <div class="child3">
              <div class="child2">
                <div class="child1">
                  1
                </div>
              </div>
            </div>
          </div>
        </div>
      </div>
      
      
        <div class="parent">
        <div class="child5">
          <div class="child4">
            <div class="child3">
              <div class="child2">
                <div class="child1">
                  2
                </div>
              </div>
            </div>
          </div>
        </div>
      </div>
      
      
        <div class="parent">
        <div class="child5">
          <div class="child4 hello">  <!-- problem here -->
            <div class="child3">
              <div class="child2">
                <div class="child1">
                  3
                </div>
              </div>
            </div>
          </div>
        </div>
      </div>

      【讨论】:

        【解决方案4】:

        使用Element.matches()query 添加对parents 的支持

        function getParents(el, query) {
          let parents = []
          while (el.parentNode !== document.body) {
            el.matches(query) && parents.push(el)
            el = el.parentNode
          }
          return parents
        }
        
        document.querySelectorAll('.child1').forEach((e, i) => {
          console.log(getParents(e, '.child4'))
        })
        <div class="parent">
          <div class="child5">
            <div class="child4">
              <div class="child3">
                <div class="child2">
                  <div class="child1">
                    1
                  </div>
                </div>
              </div>
            </div>
          </div>
        </div>
        
        
        <div class="parent">
          <div class="child5">
            <div class="child4">
              <div class="child3">
                <div class="child2">
                  <div class="child1">
                    2
                  </div>
                </div>
              </div>
            </div>
          </div>
        </div>
        
        
        <div class="parent">
          <div class="child5">
            <div class="child4 hello">
              <!-- problem here -->
              <div class="child3">
                <div class="child2">
                  <div class="child1">
                    3
                  </div>
                </div>
              </div>
            </div>
          </div>
        </div>

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2015-08-30
          • 2022-11-24
          • 1970-01-01
          • 2011-12-25
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多