I have a container with text that I want to show a read more/read less function that when clicked, displays or hides text. The problem is, I have about 10 of these containers on the same page and when I click a read more in one of the containers it affects every container on the page. I need the read more / read less function to only happen on the container where I click.
我有一个包含文本的容器,我想要显示一个多读/少读功能,当单击该功能时,将显示或隐藏文本。问题是,我在同一页面上有大约10个这样的容器,当我在其中一个容器中单击Read More时,它会影响页面上的每个容器。我需要Read More/Read Less功能只发生在我点击的容器上。
jQuery(document).ready(function($) {
var productDescription = $('.summary'),
productReadMore = $('.description-read-more'),
currentHeight = productDescription.height(),
autoHeight = productDescription.css('height', 'auto').height(),
showMoreText = 'Read More',
showLessText = 'Read Less';
productDescription.css('height', currentHeight);
productReadMore.click(function() {
if ($(this).hasClass('active')) {
$(this).removeClass('active');
productDescription.removeClass('active');
productDescription.height(currentHeight).animate({
height: currentHeight
}, 0);
productReadMore.find('.text_more').html(showMoreText);
} else {
$(this).addClass('active');
productDescription.addClass('active');
productDescription.height(currentHeight).animate({
height: autoHeight
}, 0);
productReadMore.find('.text_more').html(showLessText);
}
});
});
<div class="summary">
<p><strong>Description:</strong></p>
<p>initial content</p>
<p>more content</p>
</div>
<div class="description-read-more"><span class="text_more">Read More</span></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.4/jquery.min.js"></script>
更多回答
You use jQuery. Why do you use height
(specially in this responsive era) when jQuery provides out of the box api.jquery.com/toggle
您可以使用jQuery。当jQuery提供开箱即用的api.jquery.com/切换时,为什么要使用高度(特别是在这个响应式时代
"Why doe this work on one when I want it to work on more than one" - usually involves in forEaching (jQuery's .each()
) your set... or i.e: getting the height
on that element's click.
“当我希望它在多个设备上工作时,为什么还要在一个设备上工作”--通常涉及forEach(jQuery‘s.each())您的set...或者,即:获取该元素点击的高度。
Also, why don't you wrap the button
and the contents inside a common parent? That way you loop the parents only.
另外,为什么不把按钮和内容包装在一个共同的父级中呢?这样一来,您只需循环父级。
@RokoC.Buljan I set a height of 80px on .summary so some of the content shows. I don't want to hide all content and show all content like a toggle does.
@RokoC.Buljan我在.sum上设置了80px的高度,以便显示一些内容。我不想像切换按钮那样隐藏所有内容并显示所有内容。
优秀答案推荐
One idea, without using JavaScript, would be to animate to auto height using CSS grid
and use a checkbox (or radio) input for the toggling.
In this example I'm using the :has()
, but to support Firefox (2023. ATM)
you can place the input in the parent wrapper and reference sibling elements using ~
.
一个想法是,在不使用JavaScript的情况下,使用css网格将动画设置为自动高度,并使用复选框(或单选)输入进行切换。在本例中,我使用了:has(),但为了支持Firefox(2023)。ATM),您可以将输入放在父包装器中,并使用~引用兄弟元素。
.additional-outer {
display: grid;
grid-template-rows: 0fr;
transition: grid-template-rows 0.5s ease-in-out;
}
.additional-inner {
overflow: hidden;
}
.more {
display: inline-flex;
background: #0bf;
cursor: pointer;
padding: 0.5rem 1rem;
margin-top: 1rem;
}
.more::before {
content: "Read more";
}
.summary:has(input:checked) .more::before {
content: "Read less";
}
.summary:has(input:checked) .additional-outer {
grid-template-rows: 1fr;
}
<div class="summary">
<h3>Some title</h3>
<div class="initial">
Initial. Lorem ipsum dolor sit amet, consectetur adipisicing elit. Nesciunt iste, ut vero voluptatem exercitationem dolorem minus facilis natus, officiis porro reiciendis aspernatur ex quae enim tenetur quia dicta veniam amet.
</div>
<div class="additional-outer">
<div class="additional-inner">
Additional. Repellendus accusantium doloremque et, iusto deserunt alias, cumque totam libero officiis voluptate sunt quisquam nam, consequuntur ipsa placeat nihil. Labore at, quaerat.
</div>
</div>
<label class="more"><input type="checkbox" hidden></label>
</div>
<div class="summary">
<h3>Some other description</h3>
<div class="initial">
Initial. Adipisicing elit. Placeat illum repudiandae repellat ex accusantium neque quibusdam pariatur aut dignissimos assumenda aliquam, ducimus asperiores consequuntur sint quaerat quia porro voluptatem. Facere!
</div>
<div class="additional-outer">
<div class="additional-inner">
Additional. Temporibus nisi ut dolorum corrupti officia unde similique, atque aliquid mollitia, rem dolores, dignissimos molestias qui enim, quae repellendus repellat asperiores consectetur..
</div>
</div>
<label class="more"><input type="checkbox" hidden></label>
</div>
Use event delegation. Add a listener to the document
for which the handler only works if the event target (the element that was clicked on) has a read-more
class.
使用事件委派。将侦听器添加到处理程序仅在事件目标(被单击的元素)具有Read-More类时才对其起作用的文档。
I would then group the section that needs to be displayed within the section that's triggering its opening/closing. From there grab the summary
element of the clicked button using closest
, find the section with the text-more
class, and then toggle
it.
然后,我会对需要在触发其打开/关闭的部分中显示的部分进行分组。从那里使用Cest获取所点击按钮的摘要元素,找到包含文本-More类的部分,然后切换它。
$(document).on('click', '.read-more', function () {
$(this)
// Find the closest summary element
.closest('.summary')
// Find its text-more element
.find('.text-more')
// Toggle its class
.toggle();
});
.read-more { border: 0; }
.text-more { display: none; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<section class="summary">
<p>Section 1</p>
<button class="read-more">Read More</button>
<section class="text-more">
<p>Section 1 more text</p>
</section>
</section>
<section class="summary">
<p>Section 2</p>
<button class="read-more">Read More</button>
<section class="text-more">
<p>Section 2 more text</p>
</section>
</section>
<section class="summary">
<p>Section 3</p>
<button class="read-more">Read More</button>
<section class="text-more">
<p>Section 3 more text</p>
</section>
</section>
If you don't want to group the markup together you can use data attributes to indicate which section should be toggled instead.
如果不想将标记组合在一起,可以使用数据属性来指示应该切换哪个部分。
$(document).on('click', '.read-more', function () {
// Find the id attached to the summary section
const id = $(this).closest('.summary').data('id');
// Use the id to create a selector that matches
// the text-more section with that id
const selector = `.text-more[data-id=${id}]`;
// Use the selector to find that elenent
const $text = $(document).find(selector);
// Toggle it
$text.toggle();
});
.read-more { border: 0; }
.text-more { display: none; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<section class="summary" data-id="1">
<p>Section 1</p>
<button class="read-more">Read More</button>
</section>
<section class="text-more" data-id="1">
<p>Section 1 more text</p>
</section>
<section class="summary" data-id="2">
<p>Section 2</p>
<button class="read-more">Read More</button>
</section>
<section class="text-more" data-id="2">
<p>Section 2 more text</p>
</section>
<section class="summary" data-id="3">
<p>Section 3</p>
<button class="read-more">Read More</button>
</section>
<section class="text-more" data-id="3">
<p>Section 3 more text</p>
</section>
In jQuery when you make a search of the kind of $(someselector)
then all the items matching that selector apply. Hence, for example, productReadMore
is defined as
在jQuery中,当您搜索$(某个选择器)的类型时,将应用与该选择器匹配的所有项。因此,例如,ductReadMore被定义为
productReadMore = $('.description-read-more')
and that applies for all elements having this class. Which is good when you call the .click()
function, because it attaches a click
event for all elements having this class. However, inside the function you need to differentiate and use $(this)
rather than productReadMore
to identify the item to change rather than change all items.
这适用于所有具有这个类的元素。这在调用.Click()函数时很好,因为它为具有此类的所有元素附加了一个Click事件。然而,在函数内部,您需要区分并使用$(This)而不是ductReadMore来标识要更改的项,而不是更改所有项。
jQuery(document).ready(function($) {
var productDescription = $('.summary'),
productReadMore = $('.description-read-more'),
currentHeight = productDescription.height(),
autoHeight = productDescription.css('height', 'auto').height(),
showMoreText = 'Read More',
showLessText = 'Read Less';
productDescription.css('height', currentHeight);
productReadMore.click(function() {
productDescription = $(this).prev();
currentHeight = productDescription.height();
autoHeight = productDescription.css('height', 'auto').height();
if ($(this).hasClass('active')) {
$(this).removeClass('active');
productDescription.removeClass('active');
productDescription.height(currentHeight).animate({
height: currentHeight
}, 0);
$(this).find('.text_more').html(showMoreText);
} else {
$(this).addClass('active');
productDescription.addClass('active');
productDescription.height(currentHeight).animate({
height: autoHeight
}, 0);
$(this).find('.text_more').html(showLessText);
}
});
});
<div class="summary">
<p><strong>Description:</strong></p>
<p>initial content</p>
<p>more content</p>
</div>
<div class="description-read-more"><span class="text_more">Read More</span></div>
<div class="summary">
<p><strong>Description:</strong></p>
<p>initial content</p>
<p>more content</p>
</div>
<div class="description-read-more"><span class="text_more">Read More</span></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.4/jquery.min.js"></script>
更多回答
Cheers @mplungjan. Much more succinct.
干杯@mpengjan。简明扼要得多。
我是一名优秀的程序员,十分优秀!