寻找最近的相似兄弟姐妹

时间:2021-03-02 23:20:17

标签: javascript jquery

我希望能够点击 <i><a><li> 并获得所有 <li>

关键是要检测最接近的重复元素,无论您点击它的子元素有多深。

这是我目前所拥有的:它显示了兄弟姐妹的数量,但我想隔离的是相同性。

例如:<body> 显示 2 个兄弟姐妹,但它们不是 <body><header> 显示了 4 个,但不是全部 <header>。我如何只计算相同的兄弟姐妹。在这种情况下 <li> 但可以是任何东西。

//整页运行↗️

$('body').on('click', (e) => {
  $el = $(e.target);

  $parentsAndSelf = $el.parents().addBack();
  
  $parentsAndSelf.each( (i,el) => {
    if( $(el).siblings().addBack().length > 1){
      console.log( el,  $(el).siblings().addBack().length );
      //return false;
    }
    
  });
});
* {
  padding: 5px;
  margin:5px;
  outline: 1px solid pink;
  list-style-position: inside;
}

a {
  display: block
}

.highlight{
  background:yellow;
}

*:hover {
  outline: 1px solid red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<header>
  HEADER:
  <nav>
    NAV:
    <ul>
      UL:
      <li>li <a href="#">item <i>1</i></a> </li>
      <li>li <a href="#">item <i>2</i></a> </li>
      <li>li <a href="#">item <i>3</i></a> </li>
      <li>li <a href="#">item <i>4</i></a> </li>
    </ul>
  </nav>
</header>

3 个答案:

答案 0 :(得分:2)

这真的让我很忙呵呵。

如果:

<块引用>

关键是无论如何都要检测最近的重复元素 在你点击的孩子的深处。

意思是:

  • 你必须获得被点击元素的父元素
  • 搜索它的孩子,如果有的话,得到它的标签名(类型),如果两个相同则做出反应
  • 如果没有,请移至下一个父级,执行相同操作
<块引用>

我希望能够点击 <i><a><li> 和 获取所有 <li>

示例:

let num
document.addEventListener("click", function(event) {
  num = 1;
  let el = event.target
  let s
  check(s, el)
})

function check(s, el) {
  console.clear()

  // jumping parents part and getting only first level children
  let ss = ".parentNode"
  s = "el" + ss.repeat(num) + ".children"

  // map tagnames
  let c = [...eval(s)].map(type => type.tagName)

  // isolate duplicates part
  const yourArray = c
  const yourArrayWithoutDuplicates = [...new Set(yourArray)]
  let duplicates = [...yourArray]
  yourArrayWithoutDuplicates.forEach((item) => {
    const i = duplicates.indexOf(item)
    duplicates = duplicates
      .slice(0, i)
      .concat(duplicates.slice(i + 1, duplicates.length))
  })

  // if no duplicates call this same function just add num++ to add .parentNode
  // it will loop unitl it hits 2 same tagnames on same level, sibilings
  duplicates.length === 0 ? (num++, check(eval(s), el)) : (console.log("Repeting element :" + duplicates[0]), console.log("Repets: " + (parseInt(duplicates.length) + 1)), console.log("Position from clicked element: " + s))

}
* {
  padding: 5px;
  margin: 5px;
  outline: 1px solid pink;
  list-style-position: inside;
}

a {
  display: block
}

.highlight {
  background: yellow;
}

*:hover {
  outline: 1px solid red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<header>
  <div>1</div>
  <div>2</div>
  HEADER:
  <nav>
    NAV:
    <ul>
      UL:
      <li>li <a href="#">item <i>1</i></a> </li>
      <li>li <a href="#">item <i>2</i></a> </li>
      <li>li <a href="#">item <i>3</i></a> </li>
      <li>li <a href="#">item <i>4</i></a> </li>
    </ul>
  </nav>
</header>

编辑:

这里有一个更简化的版本,仍然遵循相同的逻辑:

let num
document.addEventListener("click", function(event) {
  num = 1;
  let s
  check(s, event.target)
})

function check(s, el) {
  console.clear()
  const ss = ".parentNode"
  s = "el" + ss.repeat(num) + ".children";
  let count = {};
  [...eval(s)].map(type => type.tagName).forEach( i => {count[i] = (count[i] || 0) + 1})
  const max = Math.max.apply(null, Object.values(count));

  max <= 1 ? (num++, check(eval(s), el)) : (console.log("Repeting element :" + Object.keys(count)[0]), console.log("Repets: " + max), console.log("Position from clicked element: " + s))
}
* {
  padding: 5px;
  margin: 5px;
  outline: 1px solid pink;
  list-style-position: inside;
}

a {
  display: block
}

.highlight {
  background: yellow;
}

*:hover {
  outline: 1px solid red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<header>
  <div>1</div>
  <div>2</div>
  HEADER:
  <nav>
    NAV:
    <ul>
      UL:
      <li>li <a href="#">item <i>1</i></a> </li>
      <li>li <a href="#">item <i>2</i></a> </li>
      <li>li <a href="#">item <i>3</i></a> </li>
      <li>li <a href="#">item <i>4</i></a> </li>
    </ul>
  </nav>
</header>

答案 1 :(得分:2)

在介绍 jQuery 之前,让我从一个非常简单的 JavaScript 想法开始:

JavaScript - 获取第一个最近的多个兄弟

这可以通过使用 Element.querySelectorAll()":scope >" 查询相同 Element.tagName 的直接子元素以及递归函数轻松实现:: >

const closestMultiple = el => {
  const par = el.parentElement;
  const sib = par && par.querySelectorAll(`:scope > ${el.tagName}`);
  return (sib && sib.length > 1 ? sib : par && closestMultiple(par))
}

document.body.addEventListener("click", (ev) => {
  const cm = closestMultiple(ev.target)
  if(cm) cm.forEach(EL => EL.classList.toggle("highlight"));
});
* {
  padding: 5px;
  margin: 5px;
  outline: 1px solid pink;
  list-style-position: inside;
  background: #fff;
}
*:hover {
  outline: 1px solid red;
}

a {
  display: block
}

.highlight {
  background: yellow;
}
<header>
  <div>
    HEADER:
  </div>
  <div>
    <nav>
      NAV:
      <ul>
        UL:
        <li>li <a href="#">item <i>1</i></a> </li>
        <li>li <a href="#">item <i>2</i></a> </li>
        <li>li <a href="#">item <i>3</i></a> </li>
        <li>li <a href="#">item <i>4</i></a> </li>
      </ul>
    </nav>
  </div>
</header>

jQuery - 获取最接近的多个兄弟姐妹

  • 使用 .reverse() 反转数组以加快从目标元素(而不是文档)开始的过程。
  • 只要 Array.prototype.some()length > 1 条件匹配,就停止循环:
function closestMultiple(el, $mu) {
  return $(el).parents().addBack().get().reverse().some(el => {
    const $gr = $(el).siblings(el.tagName).addBack();
    return ($gr.length > 1 ? $mu = $gr : 0);
  }) && $mu || $();
}

function closestMultiple(el, $mu) {
  return $(el).parents().addBack().get().reverse().some(el => {
    const $gr = $(el).siblings(el.tagName).addBack();
    return ($gr.length > 1 ? $mu = $gr : 0);
  }) && $mu || $();
}

$(document).on('click', (ev) => {
  const $clRep = closestMultiple(ev.target).toggleClass("highlight");
  console.clear(); console.log($clRep.length +" "+ $clRep.prop("tagName"));
});
* {
  padding: 5px;
  margin: 5px;
  outline: 1px solid pink;
  list-style-position: inside;
  background: #fff;
}
*:hover {
  outline: 1px solid red;
}

a {
  display: block
}

.highlight {
  background: yellow;
}
<header>
  <div>
    HEADER:
  </div>
  <div>
    <nav>
      NAV:
      <ul>
        UL:
        <li>li <a href="#">item <i>1</i></a> </li>
        <li>li <a href="#">item <i>2</i></a> </li>
        <li>li <a href="#">item <i>3</i></a> </li>
        <li>li <a href="#">item <i>4</i></a> </li>
      </ul>
    </nav>
  </div>
</header>

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>

jQuery 微插件

为了获得更好的体验(因为您已经在使用 jQuery),您可以使用自己的 jQuery 方法扩展 .closestMultiple() 构造函数。
以下是对微插件的建议:

$.fn.closestMultiple = function($mu) {
  return this.parents().addBack().get().reverse().some(el => {
    const $gr = $(el).siblings(el.tagName).addBack();
    return ($gr.length > 1 ? $mu = $gr : 0);
  }) && $mu || $();
}

$(document).on('click', (ev) => {
  $(ev.target).closestMultiple().toggleClass("highlight");
});
* {
  padding: 5px;
  margin: 5px;
  outline: 1px solid pink;
  list-style-position: inside;
  background: #fff;
}

a {
  display: block
}

.highlight {
  background: yellow;
}

*:hover {
  outline: 1px solid red;
}
<header>
  <div>
    HEADER:
  </div>
  <div>
    <nav>
      NAV:
      <ul>
        UL:
        <li>li <a href="#">item <i>1</i></a> </li>
        <li>li <a href="#">item <i>2</i></a> </li>
        <li>li <a href="#">item <i>3</i></a> </li>
        <li>li <a href="#">item <i>4</i></a> </li>
      </ul>
    </nav>
  </div>
</header>

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>

答案 2 :(得分:-2)

我认为这个简单的方法可以帮助您:

  $("i, a, li").on('click', function(event) {
      var closest_li = $(this).closest('ul').find('li');

      console.log(closest_li);
  });

因此,您将获得父 <li> 中存在的所有 <ul> 元素的数组。