Как показать только один div в то время? - PullRequest
3 голосов
/ 01 марта 2020

У меня есть три раздела, внутри которых есть два div. Внутри первой у меня есть кнопка, и после нажатия на нее у меня должна быть открыта следующая. Тем не менее, только один div должен быть виден одновременно (поэтому, когда вы нажимаете следующий, предыдущий должен быть закрыт). И у меня есть эта функциональность, но после повторного нажатия на кнопку - он не закрывает соответствующий div.

Я настроил пример моей проблемы на codepen:

https://codepen.io/hubertstrawa/pen/abOwWMJ
<section>
  <div class="product">
    <span class="btn">Show more</span>
    <p>Lorem ipsum</p>
  </div>
  <div class="product-more displayNone">
    Test
  </div>
</section>
$('.btn').click(function(e) {

  // only one div to be shown but can't be closed as well.
  $('.product-more').each(function(i, v) {
  $(this).removeClass('displayBlock');
  $(this).addClass('displayNone');
  })

  if ($(e.target).parent().next().hasClass('displayNone')) {
    $(e.target).parent().next().removeClass('displayNone');
    $(e.target).parent().next().addClass('displayBlock');
  } else {
    $(e.target).parent().next().removeClass('displayBlock');
    $(e.target).parent().next().addClass('displayNone');
  }

});

Любые идеи, как я могу заставить его работать?

Спасибо

Ответы [ 4 ]

2 голосов
/ 01 марта 2020

Изменить .is-open на родительском элементе .

<section class="product is-open">    <!-- is-open toggled by JS -->
    <div class="product-more"></div> <!-- handle children styles using CSS -->
</section>
                 .product-more { display: none; }  /* default */
.product.is-open .product-more { display: block; } /* when ancestor is .is-open*/

Используйте DelegateTarget внутри метода .on(), чтобы получить элемент делегата .product

const $product = $('.product'); // Collect all current products

$product.on('click', '.btn', function(e) {

  const $thisProd = $(e.delegateTarget);          // The .product delegator
  $product.not($thisProd).removeClass('is-open'); // Handle all (but not this)
  $thisProd.toggleClass('is-open');               // Handle current

});
/* QuickReset */ * {margin: 0; box-sizing: border-box;}

.product {
  background-color: #ededed;
  width: 400px;
  margin: 0 auto;
  margin-bottom: 1rem;
}

.product-title {
  position: relative;
  padding: 1rem;
}

.product .btn {
  position: absolute;
  bottom: 0;
  right: 0;
  padding: .7rem;
  background-color: cyan;
  cursor: pointer;
}

.product-more {
  width: 100%;
  padding: 1rem;
  background-color: cyan;
  display: none; /* by default */
}

.product.is-open .product-more {
  display: block;
}
<section class="product">
  <div class="product-title">
    <p>Lorem ipsum</p>
    <span class="btn">Show more</span>
  </div>
  <div class="product-more">Test</div>
</section>

<section class="product">
  <div class="product-title">
    <p>Lorem ipsum</p>
    <span class="btn">Show more</span>
  </div>
  <div class="product-more">Test</div>
</section>

<section class="product">
  <div class="product-title">
    <p>Lorem ipsum</p>
    <span class="btn">Show more</span>
  </div>
  <div class="product-more">Test</div>
</section>

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

Это предпочтительно, так как позволяет изменять HTML и CSS и больше не беспокоиться о JavaScript - пока используя .prev(), .next() или .parent() (как предлагают другие ответы) JS просто ждет, когда вы измените разметку - чтобы сломаться.

  • Нет необходимости перемещаться назад и вперед ваши селекторы.
  • Нет необходимости в .displayNone и .displayBlock на элементе product-more .

Обработка динамических c .product

, если ваши .product являются динамическими c элементами, вот еще одно решение вышеупомянутой концепции:

$('.allProducts').on('click', '.btn', function(e) {

  const $product = $(e.delegateTarget).find('.product'); // Get all .product
  const $thisProd = $(this).closest('.product'); // The closest .product ancestor
  $product.not($thisProd).removeClass('is-open'); // Handle all (but not this)
  $thisProd.toggleClass('is-open'); // Handle current

});
/* QuickReset */ * {margin: 0; box-sizing: border-box;}

.product {
  background-color: #ededed;
  width: 400px;
  margin: 0 auto;
  margin-bottom: 1rem;
}

.product-title {
  position: relative;
  padding: 1rem;
}

.product .btn {
  position: absolute;
  bottom: 0;
  right: 0;
  padding: .7rem;
  background-color: cyan;
  cursor: pointer;
}

.product-more {
  width: 100%;
  padding: 1rem;
  background-color: cyan;
  display: none; /* by default */
}

.product.is-open .product-more {
  display: block;
}
<div class="allProducts">

  <section class="product">
    <div class="product-title">
      <p>Lorem ipsum</p>
      <span class="btn">Show more</span>
    </div>
    <div class="product-more">Test</div>
  </section>

  <section class="product">
    <div class="product-title">
      <p>Lorem ipsum</p>
      <span class="btn">Show more</span>
    </div>
    <div class="product-more">Test</div>
  </section>

  <section class="product">
    <div class="product-title">
      <p>Lorem ipsum</p>
      <span class="btn">Show more</span>
    </div>
    <div class="product-more">Test</div>
  </section>

</div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
1 голос
/ 01 марта 2020

Вы можете использовать toggleClass, он обнаружит ваш класс и изменит его на другой.

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

Codepen

https://codepen.io/nasser-ali-karimi/pen/rNVwwLy?editors=1010

$('.btn').click(function(e) {

  // only one div to be shown but can't be closed as well.
  $('.product-more').each(function(i, v) {
    $(this).removeClass('displayBlock');
    $(this).addClass('displayNone');
  })
 $(e.target).parent().next().toggleClass('displayNone displayBlock');

});
1 голос
/ 01 марта 2020

Более короткая версия с использованием jQuery будет использовать hide () и toggle ():

$('.btn').click(function(e) {
  var more = $(e.target).parent().next() ;
  $('.product-more').not(more).hide();
  $(e.target).parent().next().toggle();
});
1 голос
/ 01 марта 2020

Вы скрываете все секции product-more при нажатии любой кнопки btn, а затем пытаетесь показать / скрыть секцию product-more, связанную с нажатой кнопкой.

Итак, когда секция product-more уже отображается, и вы нажимаете кнопку btn, в результате чего вы сначала скрываете связанный раздел, а затем код проверяет, не виден ли он, а затем показывает его снова.

Одним из возможных решений является отменить связанный product-more раздел при сокрытии. Кроме того, поскольку div s показаны по умолчанию, вам не нужен класс displayBlock.

$('.btn').click(function(e) {
    var $current = $(e.target).parent().next('.product-more');

    // Hide all sections that are not the one associated to the current button.
    $('.product-more').not($current).addClass('displayNone');

    // Show or hide current section.
    $current.toggleClass('displayNone');
});
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...