最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

nested lists - Javascript: Remove class from siblings and children of click target - Stack Overflow

programmeradmin0浏览0评论

I am trying to build something akin to the OS X Finder. Select an element from a top level list and add class to it for styling and to show child list, then select an element of child list. I have this working. The problem is removing the "active" class from the top level item when a sibling is clicked. Also, removing "active" from any child list item when a top level item is clicked.

In essence: how do I select all siblings of the click even target, and how do I select all children of the click event target.

I know this would be easy with jquery, but I am not able to use jquery on this project.

Here is what I have so far:

var allThings = document.querySelectorAll('.thing'); //all tabs on page

function clickHandler(e) {
	e.preventDefault();
	//var siblings = getSiblings(e.target);
  //console.log("siblings = " + siblings);
  //for (var i = 0; i < siblings.length; i++) {
    //siblings[i].classList.remove("active");
  //}
  //e.target.nextSibling.classList.remove("active");
  //e.target.previousSibling.classList.remove("active");
	e.target.classList.toggle("active");
};

function getSiblings(el, filter) {
  var siblings = [];
  el = el.parentNode.firstChild;
  do { if (!filter || filter(el)) siblings.push(el); } 						while (el = el.nextSibling);
  return siblings;
}

for (var i = 0; i < allThings.length; i++) {
    allThings[i].onclick = clickHandler;
    //allThings[i].children.classList.remove("active");
}
ul {
  display: inline-block;
  vertical-align: top;
}

.thing {
  position: relative;
  background: white;
}

.thing ul {
  display: none;
}

.thing.active {
  background: #ddd;
}

.thing.active > ul {
  display: inline-block;
  position: absolute;
  top: 0;
  left: 100%;
}
<ul>
  <li class="thing">First 001
    <ul>
      <li class="thing">Second 001
        <ul>
          <li class="thing">Third 001</li>
          <li class="thing">Third 002</li>
        </ul>
      </li>
    </ul>
  </li>
  <li class="thing">First 002
    <ul>
      <li class="thing">Second 002
        <ul>
          <li class="thing">Third 011</li>
          <li class="thing">Third 012</li>
        </ul>
      </li>
    </ul>
  </li>
  <li class="thing">First 003
    <ul>
      <li class="thing">Second 031
        <ul>
          <li class="thing">Third 031</li>
          <li class="thing">Third 032</li>
        </ul>
      </li>
    </ul>
  </li>
</ul>

I am trying to build something akin to the OS X Finder. Select an element from a top level list and add class to it for styling and to show child list, then select an element of child list. I have this working. The problem is removing the "active" class from the top level item when a sibling is clicked. Also, removing "active" from any child list item when a top level item is clicked.

In essence: how do I select all siblings of the click even target, and how do I select all children of the click event target.

I know this would be easy with jquery, but I am not able to use jquery on this project.

Here is what I have so far:

var allThings = document.querySelectorAll('.thing'); //all tabs on page

function clickHandler(e) {
	e.preventDefault();
	//var siblings = getSiblings(e.target);
  //console.log("siblings = " + siblings);
  //for (var i = 0; i < siblings.length; i++) {
    //siblings[i].classList.remove("active");
  //}
  //e.target.nextSibling.classList.remove("active");
  //e.target.previousSibling.classList.remove("active");
	e.target.classList.toggle("active");
};

function getSiblings(el, filter) {
  var siblings = [];
  el = el.parentNode.firstChild;
  do { if (!filter || filter(el)) siblings.push(el); } 						while (el = el.nextSibling);
  return siblings;
}

for (var i = 0; i < allThings.length; i++) {
    allThings[i].onclick = clickHandler;
    //allThings[i].children.classList.remove("active");
}
ul {
  display: inline-block;
  vertical-align: top;
}

.thing {
  position: relative;
  background: white;
}

.thing ul {
  display: none;
}

.thing.active {
  background: #ddd;
}

.thing.active > ul {
  display: inline-block;
  position: absolute;
  top: 0;
  left: 100%;
}
<ul>
  <li class="thing">First 001
    <ul>
      <li class="thing">Second 001
        <ul>
          <li class="thing">Third 001</li>
          <li class="thing">Third 002</li>
        </ul>
      </li>
    </ul>
  </li>
  <li class="thing">First 002
    <ul>
      <li class="thing">Second 002
        <ul>
          <li class="thing">Third 011</li>
          <li class="thing">Third 012</li>
        </ul>
      </li>
    </ul>
  </li>
  <li class="thing">First 003
    <ul>
      <li class="thing">Second 031
        <ul>
          <li class="thing">Third 031</li>
          <li class="thing">Third 032</li>
        </ul>
      </li>
    </ul>
  </li>
</ul>

https://jsfiddle/samhadr/ym2Lx7sn/6/

Share Improve this question asked Nov 16, 2017 at 22:21 samhadrsamhadr 351 silver badge5 bronze badges 1
  • I will go more to a CSS solution than a JS solution for this. In your CSS, create rules that matches what you expect, so for example, if you want that all your childs of an element with X class, create a rule like: .active > * so when the parent has this class, all the childs will have that rule activated – Frankusky Commented Nov 16, 2017 at 22:28
Add a ment  | 

1 Answer 1

Reset to default 5

A click event should do two things:

  1. Remove class active from all sibling and descendant elements.
  2. Add class active to the clicked element.

A querySelectorAll can help with part 1, while part 2 is quite direct:

function clickHandler( e ) {

    e.preventDefault();

    e.target.parentElement.querySelectorAll( ".active" ).forEach( e =>
        e.classList.remove( "active" ) );

    e.target.classList.add( "active" );

};
发布评论

评论列表(0)

  1. 暂无评论