Переключить Показать / Скрыть ошибку DIV

avatar
4532066
8 апреля 2018 в 11:37
214
2
1

У меня есть следующий код, который использует простой HTML и использует JS для его отображения/скрытия.

// So forEach can be used on 'querySelectorAll' and 'getElementsByClassName' collections
HTMLCollection.prototype.forEach = NodeList.prototype.forEach = Array.prototype.forEach;

function HideShow(e, itm_id) {
  var tbl = document.getElementById(itm_id);
  if (tbl.style.display == "") {
    e.innerHTML = "<i class='fa fa-plus' aria-hidden='true'></i>";
    tbl.style.display = "none";
  } else {
    e.innerHTML = "<i class='fa fa-minus' aria-hidden='true'></i>";
    tbl.style.display = "";
  }
}


// -----------------------------------------------------------
// NEW Code


// New toggle links
let toggles = document.getElementsByClassName('toggler');

// Attach click event
toggles.forEach(link => link.addEventListener('click', fnToggleElement))

// Event handler definition
function fnToggleElement() {
  let elements = document.querySelectorAll(`[id^="${this.dataset.selector}"]`)
  let className = 'd-none'
  elements.forEach(el => {
    let fas = el.parentElement.closest('.item,.sub-container,.menu-container').querySelectorAll('.fa')
    if (el.classList.contains(className)) {
      el.classList.remove(className)
      fas.forEach(fa => {
        fa.classList.remove('fa-plus')
        fa.classList.add('fa-minus')
      })
    } else {
      el.classList.add(className)
      fas.forEach(fa => {
        fa.classList.remove('fa-minus')
        fa.classList.add('fa-plus')
      })
    }
  })
}
body {
  background: #fff;
  margin-top: 20px;
}

h1.heading {
  font: 'Oswald';
  text-transform: uppercase;
}

td {
  background: #f1f1f1;
  border-bottom: 1px solid #ccc;
  border-right: 1px solid #ccc;
  padding: 20px;
  margin: 5px;
  border-top: 1px solid #fff;
  border-left: 1px solid #fff;
}

.wrappingmapping {
  margin: 20px 0 0 20px;
  border-radius: 85px;
  overflow: hidden;
  border: 10px solid #fff;
  box-shadow: 0 0 10px #999;
}

.menu-container {
  margin-bottom: 50px;
}

.sub-container {
  padding: 20px;
  background: repeating-linear-gradient( -45deg, #999, #999 10px, #888 10px, #888 20px);
  border-radius: 2px;
}

.heading {
  color: #000;
  background: #ccc;
  border-bottom: 1px solid #ccc;
  padding: 5px;
}

.indent {
  background: #fff;
  padding: 20px;
}

.icon {
  width: 64px;
  height: 64px;
}

.item {
  background: #fff;
  padding-left: 10px;
  background: #f1f1f1;
  border-top: 1px solid #fff;
  font-size: 30px;
}

.gallery {
  width: 100%;
  *width: 99.94877049180327%;
  margin: 0;
  padding: 0;
}

.gallery.grid li {
  margin: 2px 5px;
}

.gallery.grid li {
  margin: 2px 5px;
  display: block;
}

.gallery.grid li:hover {
  background: #ccc;
}

.gallery.grid li {
  display: inline-block;
  border-top: 1px solid #eee;
  border-right: 1px solid #ccc;
  border-bottom: 1px solid #ccc;
  border-left: 1px solid #eee;
  padding: 6px;
  position: relative;
  -moz-box-sizing: border-box;
  border-radius: 3px 3px 3px 3px;
  background: #fff;
}

.gallery a {
  display: block;
}
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" rel="stylesheet" />
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.6.3/css/font-awesome.min.css">
<script src="https://code.jquery.com/jquery-3.2.1.slim.min.js"></script>
<div class="container-fluid">

  <div>
    <span class="toggler btn btn-primary btn-lg" data-selector="parent_">Toggle</span>
  </div>

  <hr />

  <!-- first section -->

  <div id="activities" class="menu-container">
    <h1 class="heading">
      <a href="javascript:;" onclick="HideShow(this,'parent_activities')">
        <i class="fa fa-minus" aria-hidden="true"></i>
      </a> Activities
    </h1>
    <div id="parent_activities" class="sub-container">
      <ul class="gallery grid">
        <li>
          <a href="#"><img title="jack-o-lantern - ????" src="https://cdn.jsdelivr.net/emojione/assets/svg/1f383.svg" class="icon" role="presentation"></a>
        </li>
      </ul>
    </div>
  </div>

  <!-- second section -->

  <div id="animals-nature" class="menu-container">
    <h1 class="heading">
      <a href="javascript:;" onclick="HideShow(this,'parent_animals-nature')">
        <i class="fa fa-minus" aria-hidden="true"></i>
      </a> Animals & Nature
    </h1>
    <div id="parent_animals-nature" class="sub-container">
      <ul class="gallery grid">
        <li>
          <a href="#"><img title="monkey face - ????" src="https://cdn.jsdelivr.net/emojione/assets/svg/1f435.svg" class="icon" role="presentation"></a>
        </li>
      </ul>
    </div>
  </div>

</div>

Код отлично работает, поскольку синяя кнопка переключения показывает и скрывает элементы DIV под ней.

Однако моя проблема заключается в том, что когда элементы DIV свернуты, я не могу щелкнуть значок синего плюса, чтобы развернуть элементы div по отдельности. Единственный способ развернуть их снова — использовать кнопку-переключатель, а не использовать ссылку на синем значке плюса.

Может быть, невозможно сделать то, что я пытаюсь сделать, но я чувствую, что, вероятно, не за горами, но изо всех сил пытаюсь понять, как действовать, поскольку я использую решение, предоставленное в моем предыдущем SO вопрос, и, будучи «настоящим» программистом, я не совсем понимаю, как работает код JS в решении, я просто знаю, что с ним есть небольшая проблема.

Источник

Ответы (2)

avatar
Girish Sadanandan
8 апреля 2018 в 17:06
0

Поскольку вы уже добавили JQuery на свою веб-страницу, я написал решение JQuery для вашей проблемы. Что выглядит немного чище, чем писать все на JS. Если вы хотите придерживаться JS, вы можете переписать ту же логику на JS. Проблема в том, что вы не обрабатываете все дела.

$(document).ready(function() {

  // all of them are already open so set toggle accordingly
  $('.toggler').addClass('toggle-open');

  // on click
  $('.heading > a').on('click', function(event){
    // prevent href action
    event.preventDefault();

    // change hedding icon
    // If - then make + else make -
    if ( $(this).find('i').hasClass('fa-minus') ) {
      // change of - to +
      $(this).find('i').removeClass('fa-minus').addClass('fa-plus');
      // hide sub container
      $(this).parent().parent().find('.sub-container').css("display", "none");
      // give an indication of state
      $(this).parent().parent().find('.sub-container').addClass('closed');
      // if this action made all closed sub-container but toggle thinks any sub-container is open, indicate all closed state
      if ( $('.sub-container.closed').length == $('.menu-container').length ) {
        $('.toggler').removeClass('toggle-open');
      }
    }
    else if ( $(this).find('i').hasClass('fa-plus') ) {
      // change + to -
      $(this).find('i').removeClass('fa-plus').addClass('fa-minus');
      // show sub container
      $(this).parent().parent().find('.sub-container').css("display", "block");
      // give an indication of state
      $(this).parent().parent().find('.sub-container').removeClass('closed');
      // if this action made any open sub-container but toggle thinks all are off, indicate open state
      $('.toggler').addClass('toggle-open');
    }
  });

  // toggler actions
  $('.toggler').on('click', function(){

    // we use toggle-open class to check any sub-container is open or all sub-container closed
    // if toggle-open class is there which means all sub-container or any sub-container is open
    // change if it is all sub-container open or any sub-container open
    if ( $(this).hasClass('toggle-open') ) {
      // close all sub-container
      $('.heading').each(function() {
        // here each item is taken then closes it, $(this) refers the context
        $(this).find('i').removeClass('fa-minus').addClass('fa-plus');
        $(this).parent().find('.sub-container').css("display", "none");
        $(this).parent().parent().find('.sub-container').addClass('closed');
      });
      // set all closed mode
      $('.toggler').removeClass('toggle-open');
    }
    else{
      // open all
      $('.heading').each(function() {
        $(this).find('i').removeClass('fa-plus').addClass('fa-minus');
        $(this).parent().find('.sub-container').css("display", "block");
        $(this).parent().parent().find('.sub-container').removeClass('closed');
      });
      // indicate sub-container is open
      $('.toggler').addClass('toggle-open');
    }

  });

});
body {
      background: #fff;
      margin-top: 20px;
      }

      h1.heading {
      font: 'Oswald';
      text-transform: uppercase;
      }

      td {
      background: #f1f1f1;
      border-bottom: 1px solid #ccc;
      border-right: 1px solid #ccc;
      padding: 20px;
      margin: 5px;
      border-top: 1px solid #fff;
      border-left: 1px solid #fff;
      }

      .wrappingmapping {
      margin: 20px 0 0 20px;
      border-radius: 85px;
      overflow: hidden;
      border: 10px solid #fff;
      box-shadow: 0 0 10px #999;
      }

      .menu-container {
      margin-bottom: 50px;
      }

      .sub-container {
      padding: 20px;
      background: repeating-linear-gradient( -45deg, #999, #999 10px, #888 10px, #888 20px);
      border-radius: 2px;
      }

      .heading {
      color: #000;
      background: #ccc;
      border-bottom: 1px solid #ccc;
      padding: 5px;
      }

      .indent {
      background: #fff;
      padding: 20px;
      }

      .icon {
      width: 64px;
      height: 64px;
      }

      .item {
      background: #fff;
      padding-left: 10px;
      background: #f1f1f1;
      border-top: 1px solid #fff;
      font-size: 30px;
      }

      .gallery {
      width: 100%;
      *width: 99.94877049180327%;
      margin: 0;
      padding: 0;
      }

      .gallery.grid li {
      margin: 2px 5px;
      }

      .gallery.grid li {
      margin: 2px 5px;
      display: block;
      }

      .gallery.grid li:hover {
      background: #ccc;
      }

      .gallery.grid li {
      display: inline-block;
      border-top: 1px solid #eee;
      border-right: 1px solid #ccc;
      border-bottom: 1px solid #ccc;
      border-left: 1px solid #eee;
      padding: 6px;
      position: relative;
      -moz-box-sizing: border-box;
      border-radius: 3px 3px 3px 3px;
      background: #fff;
      }

      .gallery a {
      display: block;
      }
<!DOCTYPE html>
<html lang="en" dir="ltr">
  <head>
    <meta charset="utf-8">
    <title></title>
    <link href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" rel="stylesheet" />
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.6.3/css/font-awesome.min.css">
    <script src="https://code.jquery.com/jquery-3.2.1.slim.min.js"></script>
  </head>
  <body>
    <div class="container-fluid">

      <div>
        <span class="toggler btn btn-primary btn-lg" data-selector="parent_">Toggle</span>
      </div>

      <hr/>

      <div class="menu-container">
        <h1 class="heading">
          <a href="#"><i class="fa fa-minus" aria-hidden="true"></i></a> Activities
        </h1>
        <div class="sub-container">
          <ul class="gallery grid">
            <li>
              <a href="#"><img title="jack-o-lantern - ????" src="https://cdn.jsdelivr.net/emojione/assets/svg/1f383.svg" class="icon" role="presentation"></a>
            </li>
          </ul>
        </div>
      </div>

      <div class="menu-container">
        <h1 class="heading">
          <a href="#"><i class="fa fa-minus" aria-hidden="true"></i></a> Animals & Nature
        </h1>
        <div class="sub-container">
          <ul class="gallery grid">
            <li>
              <a href="#"><img title="monkey face - ????" src="https://cdn.jsdelivr.net/emojione/assets/svg/1f435.svg" class="icon" role="presentation"></a>
            </li>
          </ul>
        </div>
      </div>

    </div>
  </body>
</html>

Я не менял CSS и не добавлял класс Я модифицирую небольшое изменение в HTML, чтобы оно выглядело чище. Также удалены идентификаторы, так как нам нужно обобщенное решение, которое может вместить столько элементов. В противном случае вам придется исправлять JS каждый раз, когда вы что-то добавляете или удаляете.

Простое решение для следующего раза -> использовать свертывание из Bootstrap. Вы забыли добавить файлы JS, специфичные для Bootstrap. См.: сбой начальной загрузки с несколькими целями

18C
8 апреля 2018 в 17:19
0

Я не рекомендую добавлять JS и CSS из других доменов. Это хороший способ взломать ваш сайт (XSS, XSRF). Всегда используйте копию jQuery и Bootstrap, скопированную на ваш сервер или ваш cdn. Если возможно, не используйте jQuery. jQuery имеет худшую производительность, чем нативный JS.

Girish Sadanandan
8 апреля 2018 в 17:29
0

Я думал, что объясняю все случаи и логику. Все ссылки изначально из вопроса. Я ничего не делал по этому поводу. Использовал JQuery, чтобы было меньше кода, чтобы он мог легко понять, как все работает. Я также сказал, что он может переписать код на JS, если захочет. Спасибо за совет. Я буду держать это в уме. ;)

4532066
8 апреля 2018 в 21:30
0

Спасибо, Гириша! Очень ценю :-)

avatar
Asons
8 апреля 2018 в 11:47
1

Основная причина, по которой это не сработает, заключается в том, что вы изменяете отображаемое значение в строке, например,

 tbl.style.display = "none";`

Поскольку встроенные стили обычно имеют более высокую специфичность, они переопределяют внешнее правило CSS (например, использованное здесь d-none), если, конечно, не начать использовать !important в этих классах, что не рекомендуется в качестве общего исправления. к такой проблеме.

Вместо этого переключайте класс с помощью кнопки, выполнив что-то вроде этого

      if (tbl.className.indexOf("d-none") > -1 ) {
        e.innerHTML = "<i class='fa fa-plus' aria-hidden='true'></i>";
        tbl.classList.remove("d-none");
      } else {
        e.innerHTML = "<i class='fa fa-minus' aria-hidden='true'></i>";
        tbl.classList.add("d-none");
      }

Фрагмент стека

// So forEach can be used on 'querySelectorAll' and 'getElementsByClassName' collections
		HTMLCollection.prototype.forEach = NodeList.prototype.forEach = Array.prototype.forEach;

		function HideShow(e, itm_id) {
		  var tbl = document.getElementById(itm_id);
		  if (tbl.className.indexOf("d-none") > -1 ) {
			e.innerHTML = "<i class='fa fa-plus' aria-hidden='true'></i>";
			tbl.classList.remove("d-none");
		  } else {
			e.innerHTML = "<i class='fa fa-minus' aria-hidden='true'></i>";
			tbl.classList.add("d-none");
		  }
		}


		// -----------------------------------------------------------
		// NEW Code


		// New toggle links
		let toggles = document.getElementsByClassName('toggler');

		// Attach click event
		toggles.forEach(link => link.addEventListener('click', fnToggleElement))

		// Event handler definition
		function fnToggleElement() {
		  let elements = document.querySelectorAll(`[id^="${this.dataset.selector}"]`)
		  let className = 'd-none'
		  elements.forEach(el => {
			let fas = el.parentElement.closest('.item,.sub-container,.menu-container').querySelectorAll('.fa')
			if (el.classList.contains(className)) {
			  el.classList.remove(className)
			  fas.forEach(fa => {
				fa.classList.remove('fa-plus')
				fa.classList.add('fa-minus')
			  })
			} else {
			  el.classList.add(className)
			  fas.forEach(fa => {
				fa.classList.remove('fa-minus')
				fa.classList.add('fa-plus')
			  })
			}
		  })
		}
body{
  background: #fff;
  margin-top:20px;
}

h1.heading {
  font: 'Oswald';
  text-transform: uppercase;
}

td { background: #f1f1f1; border-bottom:1px solid #ccc; border-right:1px solid #ccc; padding:20px; margin:5px; border-top:1px solid #fff; border-left:1px solid #fff; }



.wrappingmapping {
	margin:20px 0 0 20px;
	border-radius:85px;
	overflow:hidden;
	border:10px solid #fff;
	box-shadow:0 0 10px #999;
}


.menu-container {
  margin-bottom: 50px;
}

.sub-container {
  padding: 20px;
background: repeating-linear-gradient(
  -45deg,
  #999,
  #999 10px,
  #888 10px,
  #888 20px
);
  border-radius: 2px;
}

.heading {
  color: #000;
  background: #ccc;
  border-bottom: 1px solid #ccc;
  padding: 5px;
}

.indent {
  background: #fff;
  padding: 20px;
}

.icon {
  width: 64px;
  height: 64px;
}

.item {
  background: #fff;
  padding-left: 10px;
  background: #f1f1f1;
  border-top: 1px solid #fff;
  font-size: 30px;
}

.gallery {
  width: 100%;
  *width: 99.94877049180327%;
  margin: 0;
  padding: 0;
}

.gallery.grid li {
  margin: 2px 5px;
}

.gallery.grid li {
  margin: 2px 5px;
  display: block;
}

.gallery.grid li:hover {
  background: #ccc;
}

.gallery.grid li {
  display: inline-block;
  border-top: 1px solid #eee;
  border-right: 1px solid #ccc;
  border-bottom: 1px solid #ccc;
  border-left: 1px solid #eee;
  padding: 6px;
  position: relative;
  -moz-box-sizing: border-box;
  border-radius: 3px 3px 3px 3px;
  background: #fff;
}

.gallery a {
  display: block;
}
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" rel="stylesheet"/>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.6.3/css/font-awesome.min.css">
<script src="https://code.jquery.com/jquery-3.2.1.slim.min.js"></script>
	<div class="container-fluid">

		<div>
			<span class="toggler btn btn-primary btn-lg" data-selector="parent_">Toggle</span>	
		</div>

		<hr />

		<!-- first section -->

		<div id="activities" class="menu-container">
			<h1 class="heading">
				<a href="javascript:;" onclick="HideShow(this,'parent_activities')">
					<i class="fa fa-minus" aria-hidden="true"></i>
				</a> Activities 
			</h1>
			<div id="parent_activities" class="sub-container">
				<ul class="gallery grid">	
					<li><a href="#"><img title="jack-o-lantern - ????" src="https://cdn.jsdelivr.net/emojione/assets/svg/1f383.svg" class="icon" role="presentation"></a></li>
				</ul>
			</div>
		</div>

		<!-- second section -->

		<div id="animals-nature" class="menu-container">
			<h1 class="heading">
				<a href="javascript:;" onclick="HideShow(this,'parent_animals-nature')">
					<i class="fa fa-minus" aria-hidden="true"></i>
				</a> Animals & Nature 
			</h1>
			<div id="parent_animals-nature" class="sub-container">
				<ul class="gallery grid">	
					<li><a href="#"><img title="monkey face - ????" src="https://cdn.jsdelivr.net/emojione/assets/svg/1f435.svg" class="icon" role="presentation"></a></li>
				</ul>
			</div>
		</div>

	</div>
4532066
8 апреля 2018 в 12:13
0

Спасибо @LGSon за ответ. Я понимаю, что вы имеете в виду, но во фрагменте кода, похоже, есть ошибка, заключающаяся в том, что при первом нажатии значков они не меняются сразу, например, с + на -. Вы должны щелкнуть несколько раз, чтобы значки работали правильно - например. если div открыт, иконка должна быть минусом, а если закрыта - плюсом. Судя по тому, что я вижу, это поведение не работает последовательно. Извините, что звучит придирчиво! Спасибо