Ich habe mehrere „Mehr lesen“-/„Weniger lesen“-Abschnitte für eine Seite. Wenn ich einen Read More Read / Less-Abschnitt auf der Seite verwende, funktioniert das gut, wenn ich mehrere Abschnitte auf der Seite verwende, funktioniert nur ein Abschnitt, andere funktionieren nicht. Ich benötige mehrere Abschnitte, um auf derselben Seite zu arbeiten.
const content = document.querySelector(".content-inner");
const contentFull = document.querySelector(".content-full");
const more = document.querySelector(".read-more");
let open = false;
if (more) {
more.addEventListener("click", (e) => {
if (open) {
content.removeAttribute("style");
e.target.innerText = "click here";
open = false;
} else {
content.style.maxHeight = `${contentFull.clientHeight}px`;
e.target.innerText = "read less";
open = true;
}
});
}
.read-more {
display: inline-block;
margin-top: 10px;
font-weight: 400;
cursor: pointer;
font-size: 14px;
}
<div class="content">
<div class="content-inner update-modal">
<div class="content-full">
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</p>
</div>
</div>
<span class="read-more">click here</span>
</div>
Dies ist eine Aufgabe, die mit der Ereignisdelegierung zu erledigen ist. Click-Events (wie die meisten Events) sprudeln hoch document
vom angeklickten Element, und Sie können Ereignisse auf ihrem Weg nach oben erkennen.
Das folgende Beispiel zeigt Ihnen, wie Sie die Ereignisdelegierung verwenden. Der Code ist wiederverwendbar, er kann auf jeder Seite mit fast jeder Elementstruktur verwendet werden, Sie können auch Ihre Klassen und das Styling der Elemente beibehalten. Dieses Snippet kann auch auf dynamischen Seiten verwendet werden, es funktioniert, ohne dass Änderungen an JS vorgenommen werden müssen, wenn Sie erweiterbare Elemente zu den Containern hinzufügen oder daraus entfernen.
function toggleContent (options) {
const {container, expandable, triggerer, autoClose} = options,
contents = document.querySelectorAll(container),
buttonText = ['Read more', 'Read less'];
let current = null; // Keeps book of the currently open expandee
function toggle (e) {
const button = e.target;
if (!button.matches(triggerer)) {return;} // Quit, an irrelevant element clicked
const commonParent = button.closest(expandable);
if (!commonParent) {return;} // Quit, the expandable element was not found
if (autoClose && current && button !== current) {
// If autoClose is on, closes the current expandee
toggle({target: current});
}
const state = +commonParent.classList.toggle('expanded');
button.textContent = buttonText[state];
current = state ? button : null;
}
// Add click listeners to all elements containing expandables
contents.forEach(cont => cont.addEventListener('click', toggle));
}
// Activate ContentToggler
toggleContent({
container: '.expandables-container', // Selector for the elements containing expandable elements
expandable: '.expandable', // Selector for expandable elements
triggerer: '.toggle-button', // Selector for the element triggering expansion
autoClose: true // Indicates whether the expanded element is closed when a new element is expanded (optional)
});
.expandable {
border: 1px solid #000;
margin-bottom: 1em;
}
/* Hides all the expandees */
.expandable .expandee {
display: none;
}
/* Shows the expandee when .expanded is added to the parent of expandee */
.expanded .expandee {
display: block;
}
<div class="expandables-container">
<div class="expandable">
<p>Always visible content.</p>
<div class="expandee">
<p>More content.</p>
</div>
<button class="toggle-button">Read more</button>
</div>
<div class="expandable">
<p>Toggle button can be placed above the expandee element.</p>
<button class="toggle-button">Read more</button>
<div class="expandee">
<p>More content.</p>
</div>
</div>
<p>Elements can be placed between expandables.</p>
<div class="expandable">
<p>Always visible content.</p>
<div class="expandee">
<p>More content.</p>
</div>
<p>Elements can be placed between expandable and toggle button.</p>
<button class="toggle-button">Read more</button>
</div>
<div class="expandable">
<p>The only requirement is, that the toggle button and expandee are descendants of expandable.</p>
<div class="expandee">
<p>And the button must not be placed inside expandee.</p>
</div>
<button class="toggle-button">Read more</button>
</div>
</div>
Die Idee ist, dass alle Expandables in einem Element verpackt sind. Der Klick-Listener wird an diesen Wrapper angehängt, und es wird nur ein einziger Klick-Listener pro Wrapper benötigt. Dies wird als Ereignisdelegierung bezeichnet und ermöglicht es Ihnen, Inhalte jederzeit frei zum Wrapper hinzuzufügen oder daraus zu entfernen, ohne das Skript überhaupt aktualisieren zu müssen.
Alles ist eingepackt toggleContent
Funktion aus drei Gründen. Erstens kapselt es den Code, es müssen keine globalen Variablen eingeführt werden. Zweitens ermöglicht es, die Funktion mehrmals mit unterschiedlichen Parametern aufzurufen und verschiedene Arten von Umschaltern auf derselben Seite zu erstellen. Drittens ist es viel einfacher, ein kompaktes Codepaket auf eine andere Seite zu kopieren.
toggle
Funktion erhält das angeklickte Element aus dem Ereignisobjekt (e
wird automatisch aus der Ereigniswarteschlange übergeben), wenn das Element nicht mit dem übergebenen Auslöser-Selektor übereinstimmt, wird das Ereignis abgebrochen. Dann findet es den gemeinsamen Elternteil des Auslösers und das anzuzeigende Element (“expandee”) und fügt es hinzu, wenn es gefunden wird expanded
Klasse an die Eltern.
CSS zeigt den Expandee mit dem Descendant-Kombinator an .expanded .expandee
das sich auf das expandee-Element bezieht, wenn ein übergeordnetes Element vorhanden ist expanded
Klasse. Das aktuell geöffnete Expandee wird einfach geschlossen, indem dieselbe Funktion mit einem Dummy-Ereignisobjekt mit dem aktuellen Element als Ziel aufgerufen wird. Abschließend werden der Textwert des Triggers und das aktuell aktive Element aktualisiert.
Es ist bemerkenswert, dass das Beispiel ein sehr generischer Klassenumschalter ist, er ändert nur den Klassennamen des übergeordneten Elements des angeklickten Elements, und Sie können in den CSS-Regeln beliebige Stile festlegen, es muss nicht sein display
Auch height
kann verwendet werden, oder irgendetwas.
Das „Widget“ wird durch Aufruf aktiviert toggleContent
Funktion. Selektoren für die Wrapper, die erweiterbaren Elemente und die Umschaltflächen werden in einem Objekt übergeben. Der vierte Parameter steuert das automatische Schließen. Wenn Sie zu diesem Zeitpunkt nur ein einzelnes erweitertes Element sichtbar halten möchten, übergeben Sie true
beim Vorbeigehen false
oder durch Weglassen der Eigenschaft funktionieren die Umschaltflächen unabhängig voneinander.
Wenn Sie mehr Kontrolle über den umschaltbaren Inhalt benötigen, würde ich einen OOP-basierten Ansatz empfehlen. Dieses OOP-Beispiel verpackt den Code im Beispiel in dieser Antwort in eine Klasse und stellt einige Anwendungsfälle bereit, die zeigen, wie der Inhalt gesteuert wird. Wenn Sie Wind davon bekommen, wie OOP funktioniert (oder Sie es bereits wissen), können Sie der Klasse ganz einfach Methoden hinzufügen, z. zum Ausblenden/Anzeigen des gesamten Inhalts usw.
Sie müssen die relative Auswahl auswählen, um diesen Vorgang auszuführen, da sich die Klassen wiederholen. Hier die toggleReadMore-Funktion wird an jede read more-Klasse angehängt und führt die Höhenmanipulationsaktion für die innere Inhaltsklasse aus.
var prevOpened = null;
function toggleReadMore(e) {
if(prevOpened !== null && e.target !== prevOpened){
prevOpened.click();
}
// get the current section parent. This will make the selection on other class items easier.
var contentSection = e.target.closest('.content');
var contentInner = contentSection.querySelector('.content-inner');
if (e.target.textContent === "read less") {
contentInner.removeAttribute("style");
e.target.innerText = "click here";
prevClicked = null;
return;
}
contentInner.style.maxHeight = `${contentSection.querySelector('.content-full').clientHeight}px`;
e.target.innerText = "read less";
prevOpened = e.target;
}
var readMoreSections = document.querySelectorAll(".read-more");
readMoreSections.forEach(function(sections) {
sections.addEventListener("click", toggleReadMore);
})
.read-more {
display: inline-block;
margin-top: 10px;
font-weight: 400;
cursor: pointer;
font-size: 14px;
}
.content-inner {
max-height: 20px;
overflow: hidden;
}
<div class="content">
<div class="content-inner update-modal">
<div class="content-full">
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</p>
</div>
</div>
<span class="read-more">click here</span>
</div>
<div class="content">
<div class="content-inner update-modal">
<div class="content-full">
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</p>
</div>
</div>
<span class="read-more">click here</span>
</div>
Bearbeiten: Dies wurde aktualisiert, um nur das zuletzt angeklickte Element zu öffnen.
Sie müssen querySelectorAll für die mehreren Ergebnisse der Abfrage verwenden. Und wenden Sie dann den Ereignis-Listener auf jeden einzeln an.
– Rajesh Paudel
8. Dezember 2021 um 5:17 Uhr
Vielen Dank für Ihre Antwort und angesichts Ihrer prompten Zeit, sehr zu schätzen … Ich habe es gemäß Ihrem Vorschlag versucht, aber alle Funktionen zum Weiterlesen gestoppt
– Designer16
8. Dezember 2021 um 5:25 Uhr
Ich werde versuchen, Ihre Frage zu beantworten, um Ihnen dann eine bessere Vorstellung zu geben. Es hätte funktionieren sollen.
– Rajesh Paudel
8. Dezember 2021 um 5:34 Uhr