在 CSS class 和 'n' 元素上的纯 javascript 之间切换

Toggling Between a CSS class with pure javascript on 'n' elements

致力于创建功能,当用户点击其中一个产品(每个元素都具有相同的分配 ID card-reveal)时,它会向专门点击的容器添加一个 CSS class(活动状态)显示该特定项目的信息,最后,当用户单击取消按钮时,CSS class 被删除(激活状态消失)。

不幸的是,我遇到了 运行 一些问题,当我点击第一个元素时,它会向该元素添加 class,但我点击的其他元素不会添加 class ,以及关闭按钮根本不起作用。我想在 Pure Javascript 中完成解决方案。此外,如果您看到一些 classie() 方法,我正在使用 Classie.js 来帮助 CSS class 切换。

任何帮助将不胜感激!谢谢!

Html

<a  id="card-reveal" class="card-view" href="javascript:void(0)"><h3 class='hover-title'>View More</h3></a>
<div class="card-cover">
                            <span class="card-exit"></span>

                            <a class="card-follow" href="javascript:void(0)">Follow {{object.product_website_name}}.com</a>
                            <a class="card-buy" target="_blank" href="{{object.product_slug_url}}">Buy {{object.product_name }}</a>
                            <a id="card-close" class="card-info" href="javascript:void(0)"><span class="icon-indie_web-03"></span></a>
                            <ul class="card-social">
                                <label>Share</label>
                                <li><a href="#"><span  class="icon-indie_web-04"></span></a></li>
                                <li><a href="#"><span  class="icon-indie_web-05"></span></a></li> 
                            </ul>
                        </div> 

CSS

.card-cover {
    width:100%;
    height: 100%;
    background: none repeat scroll 0% 0% rgba(255, 91, 36, 0.9);
    color: #FFF;
    display: block;
    position: absolute;
    opacity: 0;
    z-index:200;
    overflow: hidden;
    -webkit-transform:translate3d(0, 400px, 0);
    transform:translate3d(0, 400px, 0);
    -webkit-backface-visibility:hidden;
     backface-visibility: hidden;
     -webkit-transition-property:opacity, transform;
    transition-property:opacity, transform;
    -webkit-transition-duration:0.2s;
    transition-duration:0.2s;
    -webkit-transition-timing-function:cubic-bezier(0.165, 0.84, 0.44, 1);
    transition-timing-function:cubic-bezier(0.165, 0.84, 0.44, 1);   
    -webkit-transition-delay: 0s;
    transition-delay: 0s;
}


 .card-cover.card--active {
    opacity: 1;
    -webkit-transform:translate3d(0, 0, 0);
    transform:translate3d(0, 0px, 0);   
}

以下JS:

var cardContainer = document.querySelector('.card-cover'),
                cardTargets = Array.prototype.slice.call( document.querySelectorAll( '#card-reveal' ) ),
                eventType =  mobilecheck() ? 'touchstart' : 'click',
                cardClose = document.getElementById('card-close'),
                resetMenu = function() {
                    classie.remove( cardContainer, 'card--active' );
                },
                resetMenuClick = function( ) {
                    cardCloseaddEventListener(globalMenuEventType, function() {
                        resetMenu();
                        document.removeEventListener(eventType, resetMenuClick);
                    }, false);      
                };

            cardTargets.forEach(function (element, index) {


                if( element.target ) {
                    element.addEventListener(eventType, function( event ) {
                        event.preventDefault();
                        event.stopPropagation();

                        classie.add(cardContainer, 'card--active');

                        document.addEventListener(eventType, resetMenuClick);
                    } ,false);
                }

            });

我可以想到两种简单的方法来做这样的事情。

首先,如果您不能为每张卡指定 ID(听起来您不能),您将不得不使用 class 名称。就像评论中提到的那样,您真的不想为多个元素使用相同的 ID。

部分原因是,正如您从我下面的示例中看到的那样,.getElementById() 方法仅适用于 return 一个元素,而其他方法如 .getElementsByClassName()将 return 一个元素数组。

我们试图解决的问题是您想要 display/hide 的子内容必须附加到您以某种方式单击的元素。由于我们没有使用 ID,并且您不能真正依赖 class 名称在元素之间是唯一的,因此我将 div 与信息放在一个容器中,该容器带有切换它的元素。

在容器 div 内,有两个 div 内容。一个是始终可见的主要内容,另一个是仅在单击主要内容时才可见的子内容(再次单击时变为不可见)。

此方法的好处是,由于无需担心 ID,您可以 copy/paste 卡片,它们每张都会显示相同的行为。

var maincontent = document.getElementsByClassName("main-content");
// Note: getElemenstByClassName will return an array of elements (even if there's only one).

for (var i = 0; i < maincontent.length; i++) {
  //For each element in the maincontent array, add an onclick event.
  maincontent[i].onclick = function(event) {

    //What this does is gets the first item, from an array of elements that have the class 'sub-content', from the parent node of the element that was clicked:
    var info = event.target.parentNode.getElementsByClassName("sub-content")[0];

    if (info.className.indexOf("show") > -1) { // If the 'sub-content' also contains the class 'show', remove the class.
      info.className = info.className.replace(/(?:^|\s)show(?!\S)/g, '');
    } else { // Otherwise add the class.
      info.className = info.className + " show";
    }
  }
}
.container {
  border: 1px solid black;
  width: 200px;
  margin: 5px;
}
.main-content {
  margin: 5px;
  cursor: pointer;
}
.sub-content {
  display: none;
  margin: 5px;
}
.show {
  /* The class to toggle */
  display: block;
  background: #ccc;
}
<div class="container">
  <div class="main-content">Here is the main content that's always visible.</div>
  <div class="sub-content">Here is the sub content that's only visible when the main content is clicked.</div>
</div>
<div class="container">
  <div class="main-content">Here is the main content that's always visible.</div>
  <div class="sub-content">Here is the sub content that's only visible when the main content is clicked.</div>
</div>
<div class="container">
  <div class="main-content">Here is the main content that's always visible.</div>
  <div class="sub-content">Here is the sub content that's only visible when the main content is clicked.</div>
</div>

第二种方法是对您想要 show/hide 的内容使用一个 div,单击一个元素将同时切换其可见性和内容。

我将使用前面的示例作为基础,但理想情况下,您会有某种 MVVM 框架,如 React、Knockout 或 angular 来帮助您填写内容。为了这个例子,我将使用子内容 div 中的文本。

var info = document.getElementById("Info");
var maincontent = document.getElementsByClassName("main-content");

for (var i = 0; i < maincontent.length; i++) { //getElemenstByClassName will return an array of elements (even if there's only one).
  maincontent[i].onclick = function(event) { //For each element in the maincontent array, add an onclick event. 

    //This does the same as before, but I'm getting the text to insert into the info card.
    var text = event.target.parentNode.getElementsByClassName("sub-content")[0].innerHTML;
    info.innerHTML = text; // Set the text of the info card.

    info.style.display = "block"; //Make the info card visible.
  }
}

info.onclick = function(event) {
  info.style.display = "none"; // If the info card is ever clicked, hide it.
}
.container {
  border: 1px solid black;
  width: 200px;
  margin: 5px;
  padding: 5px;
}
.main-content {
  margin: 5px;
  cursor: pointer;
}
.sub-content {
  display: none;
  margin: 5px;
}
#Info {
  cursor: pointer;
  display: none;
}
<div id="Info" class="container">Here is some test information.</div>
<div class="container">
  <div class="main-content">Link 1.</div>
  <div class="sub-content">You clicked link 1.</div>
</div>
<div class="container">
  <div class="main-content">Link 2.</div>
  <div class="sub-content">You clicked link 2.</div>
</div>
<div class="container">
  <div class="main-content">Link 3.</div>
  <div class="sub-content">You clicked link 3.</div>
</div>