3

我想在CSS单击元素后立即将类名添加到元素的下一个兄弟元素以获得简单的显示/隐藏效果

我有以下 html 输出,但没有元素 ID。

<div class="news-message">
  <div class="message-head"> Headline of Message 1 </div>
  <div class="message-content"> Here comes the content of message 1 </div>
</div>
<div class="news-message">
  <div class="message-head"> Headline of Message 2 </div>
  <div class="message-content"> Here comes the content of message 2 </div>
</div>
<div class="news-message">
  <div class="message-head"> Headline of Message 3 </div>
  <div class="message-content"> Here comes the content of message 3 </div>
</div>

    

现在我想隐藏消息内容,只显示标题(用 很容易实现display: none)。

一旦单击标题,我希望显示该特定消息的内容。

所以我的想法是通过单击消息头CSS向“消息内容”添加一个“可见”类,然后再次单击将其删除。DIV

所以我在“pm-head”元素和以下javascript中添加了一个“onClick="changeClass()”

function changeClass() {
  var hidecontent = document.querySelectorAll('.message-content');
  var i;
  for (i = 0; i < hidecontent.length; i++) {
    hidecontent[i].classList.toggle('visible');      }    }

但这会将类添加到该页面上的所有“消息内容”div 中,而我只需要将它添加到我单击的“pm-head”元素的下一个兄弟元素中。

而且我不能在这个上使用 jquery 或其他框架/库。

抱歉,我是 javascript 新手,可能是一个容易回答的问题。

谢谢约翰

4

3 回答 3

7

nextSibling是您寻求的答案。无需自己进行测试,但这应该对您有用:

function changeClass(e) {
    e.target.nextSibling.classList.toggle("visible");
}
于 2016-09-26T12:35:12.970 回答
1

您可以使用此代码,这需要定义一个额外的类hidden,并为每个消息内容标签添加到您的 HTML 中:

Array.from(document.querySelectorAll('.news-message'), function (elem) {
    elem.addEventListener('click', function hideContent(e) {
        e.currentTarget.querySelector('.message-content').classList.toggle('hidden');
    });
});

Array.from(document.querySelectorAll('.news-message'), function (elem) {
    elem.addEventListener('click', function hideContent(e) {
        e.currentTarget.querySelector('.message-content').classList.toggle('hidden');
    });
});
.hidden { display:none; }
<div class="news-message">
  <div class="message-head">
    Headline of Message 1
    </div>
   <div class="message-content hidden">
    Here comes the content of message 1
   </div>
</div>

<div class="news-message">
  <div class="message-head">
    Headline of Message 2
    </div>
   <div class="message-content hidden">
    Here comes the content of message 2
   </div>
</div>

<div class="news-message">
  <div class="message-head">
    Headline of Message 3
    </div>
   <div class="message-content hidden">
    Here comes the content of message 3
   </div>
</div>

请注意,虽然您可以使用,但这使用了另一种方法:它捕获对元素(即父元素)nextSibling的单击,然后定位该元素,最后切换其上的隐藏类。news-messagemessage-content

通过在父级捕获单击事件,您还可以通过单击内容本身来切换内容的显示。这可能很有用。如果您不想要这种行为,请将代码更改为:

Array.from(document.querySelectorAll('.message-head'), function (elem) {
    elem.addEventListener('click', function hideContent(e) {
        e.currentTarget.parentNode.querySelector('.message-content')
                       .classList.toggle('hidden');
    });
});

Array.from(document.querySelectorAll('.message-head'), function (elem) {
    elem.addEventListener('click', function hideContent(e) {
        e.currentTarget.parentNode.querySelector('.message-content')
                       .classList.toggle('hidden');
    });
});
.hidden { display:none; }
<div class="news-message">
  <div class="message-head">
    Headline of Message 1
    </div>
   <div class="message-content hidden">
    Here comes the content of message 1
   </div>
</div>

<div class="news-message">
  <div class="message-head">
    Headline of Message 2
    </div>
   <div class="message-content hidden">
    Here comes the content of message 2
   </div>
</div>

<div class="news-message">
  <div class="message-head">
    Headline of Message 3
    </div>
   <div class="message-content hidden">
    Here comes the content of message 3
   </div>
</div>

此变体将仅处理对标题的单击,转到其父节点,然后像以前一样从那里继续。

于 2016-09-26T12:56:52.950 回答
1

我建议,如果您能够使用 ES6:

// a named function to handle the toggling of visibility:
function toggleNextSibling(event) {

  // event.target is the element/node that triggered
  // the event:
  event.target
    // the nextElementSibling finds the next element
    // sibling of the clicked node:
    .nextElementSibling
    // we use Element.classList.toggle to add the
    // supplied class-name if it's not present, or
    // remove the supplied class-name if it is
    // present:
    .classList.toggle('shown');
}

// here we document.querySelectorAll() to retrieve a (non-live)
// NodeList of the elements of the document that match the
// supplied CSS selector, this NodeList is then passed to
// Array.from() to convert the Array-like NodeList into an
// Array:
Array.from(document.querySelectorAll('.message-head'))

  // as we have an Array we can then use Array.prototype.forEach()
  // to iterate over each element of the Array to perform actions
  // upon them:
  .forEach(

    // 'head' is a reference to the Array element of the Array
    // over which we're iterating, and upon each of those
    // Array elements we're then using addEventListener() to
    // bind a function (toggleNextSibling()) as the event-
    // handler for the 'click' event (but note the deliberate 
    // absence of parentheses following the function name):
    head => head.addEventListener('click', toggleNextSibling)
  );

function toggleNextSibling(event) {
  event.target.nextElementSibling.classList.toggle('shown');
}

Array.from(document.querySelectorAll('.message-head'))
  .forEach(head => head.addEventListener('click', toggleNextSibling));
.message-head {
  cursor: pointer;
  margin: 0.5em 0 0 0;
}
.news-message:first-child.message-head {
  margin-top: 0;
}
.message-content {
  display: none;
  text-indent: 1em;
  color: rebeccapurple;
}
.message-content.shown {
  display: block;
}
<div class="news-message">
  <div class="message-head">
    Headline of Message 1
  </div>
  <div class="message-content">
    Here comes the content of message 1
  </div>
</div>

<div class="news-message">
  <div class="message-head">
    Headline of Message 2
  </div>
  <div class="message-content">
    Here comes the content of message 2
  </div>
</div>

<div class="news-message">
  <div class="message-head">
    Headline of Message 3
  </div>
  <div class="message-content">
    Here comes the content of message 3
  </div>
</div>

如果没有 ES6,上面的内容可以转换为以下内容(尽管函数本身不需要更改):

// here we use Function.prototype.call(), to enable us to
// pass the NodeList to Array.prototype.slice(), which converts
// the NodeList to an Array:
Array.prototype.slice.call(document.querySelectorAll('.message-head'))

  // again, having an Array allows us to use Array methods, but
  // here we cannot use Arrow function expressions (as they were
  // not available until ES6), so instead we use a function expression:
  .forEach(function(head) {

    // 'head' refers to the current Array element of the Array
    // over which we're iterating, and we again use addEventListener
    // to bind the named function to the 'click' event:
    head.addEventListener('click', toggleNextSibling)
  });

function toggleNextSibling(event) {
  event.target.nextElementSibling.classList.toggle('shown');
}

Array.prototype.slice.call(document.querySelectorAll('.message-head'))
  .forEach(function(head) {
    head.addEventListener('click', toggleNextSibling)
  });
.message-head {
  cursor: pointer;
  margin: 0.5em 0 0 0;
}
.news-message:first-child.message-head {
  margin-top: 0;
}
.message-content {
  display: none;
  text-indent: 1em;
  color: rebeccapurple;
}
.message-content.shown {
  display: block;
}
<div class="news-message">
  <div class="message-head">
    Headline of Message 1
  </div>
  <div class="message-content">
    Here comes the content of message 1
  </div>
</div>

<div class="news-message">
  <div class="message-head">
    Headline of Message 2
  </div>
  <div class="message-content">
    Here comes the content of message 2
  </div>
</div>

<div class="news-message">
  <div class="message-head">
    Headline of Message 3
  </div>
  <div class="message-content">
    Here comes the content of message 3
  </div>
</div>

于 2016-09-26T13:07:11.090 回答