纯Javascript获得父母

时间:2019-06-14 11:47:18

标签: javascript

我根据.parents() without jquery - or querySelectorAll for parents

创建了一个代码段

  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>

如果没有<div class="child4 hello">的{​​{1}}我可以得到所有hello,如果添加了child4或其他任何内容,我将无法得到hello。我使用的child4应该不是indexOf()或未定义。有人可以纠正我错误在哪里吗?谢谢

4 个答案:

答案 0 :(得分:3)

问题在于,您将获取元素列表,并将其映射到元素的className,而当目标元素仅包含child4类时,数组将为child4 hello,当您在数组中寻找child4值的索引时,child4 hello将不匹配。可以使用Array.indexOf代替Array.find

  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属性,因为它具有contains函数。

答案 1 :(得分:2)

您可以像这样使用Array原型的findIndexreturn parents[parents.map(x => x.className).findIndex(x => x.indexOf(_class) > -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>

答案 2 :(得分:2)

问题在于,当您执行parents.map(x => 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>

此代码将与 string 一起使用:

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 :(得分:1)

使用Element.matches()android:networkSecurityConfig="@xml/network_security_config" 的{​​{1}}添加支持

query
parents