Изменить .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>