Es ist eine häufige Anforderung in Webanwendungen: Sie klicken auf etwas und der Text des angeklickten Elements ändert sich. Vielleicht etwas Einfaches wie ein "Anzeigen"-Button, der zu "Ausblenden" wird, oder "Beschreibung erweitern" zu "Beschreibung einklappen". Das ist relativ einfach zu bewerkstelligen, aber es gibt verschiedene Aspekte zu beachten. Lassen Sie uns eine Reihe von Möglichkeiten abdecken.
jQuery-Weg (weniger Markup / mehr JavaScript)
Sie müssen den "Austausch"-Text irgendwo speichern. Ich würde sagen, in den meisten Fällen ist dies eine Design-/Ansicht-Angelegenheit, daher ist die Speicherung im Markup eine gute Idee. Wir verwenden das Beispiel eines Buttons, dessen Text zwischen "Ausblenden" und "Anzeigen" wechselt. Ein data-* Attribut ist ein durchaus geeigneter Ort, um den Austauschtext zu speichern. Das wird dann zu
<button data-text-swap="Show">Hide</button>
Es ist einfach, den Text auszutauschen, z.B.
var button = $("button");
button.text(button.data("text-swap"));
Aber wenn wir das täten, würden wir den Originaltext für immer verlieren. Wir müssen den Originaltext zuerst speichern. Ein weiteres data-* Attribut wird ausreichen.
var button = $("button");
button.data("text-original", button.text());
button.text(button.data("text-swap"));
Um das bei einem Klick-Ereignis zu tun, würden Sie
var button = $("button");
button.on("click", function() {
button.data("text-original", button.text());
button.text(button.data("text-swap"));
});
Aber das geht nur in eine Richtung. Um den "Austausch" abzuschließen, müssen wir den aktuellen Textwert des Buttons vergleichen, um zu sehen, ob er mit dem Austauschtext übereinstimmt oder nicht. Wenn ja, ändern Sie ihn zurück zum Original. Wenn nicht, zum Austauschtext. So sieht das komplett aus
$("button").on("click", function() {
var el = $(this);
if (el.text() == el.data("text-swap")) {
el.text(el.data("text-original"));
} else {
el.data("text-original", el.text());
el.text(el.data("text-swap"));
}
});
jQuery-Weg (mehr Markup / weniger JavaScript)
Wenn wir bereit sind, den Wert data-text-original im ursprünglichen Markup zu setzen, können wir das JavaScript etwas vereinfachen. Wir können einen einzelnen ternären Operator verwenden, um zu prüfen, ob der Austausch dem Original entspricht, und die richtige Aktion basierend auf der Wahrhaftigkeit ausführen.
$("button").on("click", function() {
var el = $(this);
el.text() == el.data("text-swap")
? el.text(el.data("text-original"))
: el.text(el.data("text-swap"));
});
Vanilla-JavaScript-Weg
Ich bin schuldig, zu viel jQuery für Dinge zu verwenden, die auch ohne es getan werden können. So würde die erste "weniger Markup"-Version in "rohem" JavaScript aussehen
var button = document.querySelectorAll("button")[0];
button.addEventListener('click', function() {
if (button.getAttribute("data-text-swap") == button.innerHTML) {
button.innerHTML = button.getAttribute("data-text-original");
} else {
button.setAttribute("data-text-original", button.innerHTML);
button.innerHTML = button.getAttribute("data-text-swap");
}
}, false);
CSS-Weg (mit jQuery, das Klassennamen ändert)
Da dies eine Ansichtssache ist und als "Zustand" betrachtet werden kann, ist eine gängige Idee, JavaScript nur zu verwenden, um Klassen zu ändern, die Zustände darstellen, und CSS zu definieren, was die visuelle Änderung tatsächlich ist.
Wir könnten die Klasse "on" verwenden, um den Austauschzustand darzustellen. Dann wendet diese Klasse ein Pseudoelement an, das das alte Wort überdeckt und es durch das Austauschwort ersetzt. Ich glaube nicht, dass tatsächliche Button-Elemente mit Standard-Browser-Styling gut mit Pseudoelementen zurechtkommen, also verwenden wir hier einen Anker.
a {
position: relative;
}
a.on:after {
content: "Hide";
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: white;
}
Das ist zugegebenermaßen etwas seltsam. Ich denke, das ist fast schlimmer, als das Austauschwort in das JavaScript zu stecken. CSS ist eigentlich nicht für diese Art von Dingen gedacht und hat wahrscheinlich einige Barrierefreiheitsprobleme.
Das funktioniert auch, weil das Wort "Ausblenden" etwas kleiner ist als "Anzeigen". Wenn das Austauschwort größer wäre, würde das Original darunter hervorstechen. Sie könnten das vielleicht umgehen, indem Sie das Original mit inline-block versehen, den Überlauf ausblenden und das Original mit text-indent aus dem Feld schieben. Aber die Tatsache, dass das Ersetzungswort absolut positioniert ist, entfernt es aus dem Fluss, was ein Problem sein könnte, ganz zu schweigen davon, dass ein reales Design nicht immer so einfach ist wie flache Farbe auf flacher Farbe.
Nur-CSS-Weg
Aber hey, solange wir schon seltsam werden, könnten wir The Checkbox Hack verwenden, um den Text komplett über CSS austauschen zu lassen. Die Ersetzung erfolgt auf exakt dieselbe Weise, sie passiert nur, wenn eine unsichtbare Checkbox direkt vor dem Wort entweder :checked oder nicht ist. Das bedeutet, dass das Wort auch in einem Label stehen muss, das den Zustand der Checkbox über das for-Attribut umschalten kann.
<input id="example-checkbox" type="checkbox">
<label for="example" id="example">Show</label>
#example {
position: relative;
}
#example-checkbox {
display: none;
}
#example-checkbox:checked + #example:after {
content: "Hide";
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: white;
}
Demo aller fünf Wege
Check out this Pen!
Mehr?
Wie haben Sie das bisher gemacht? Wir haben nicht behandelt, den Austauschtext einfach in das JavaScript zu schreiben ... wie stehen Sie dazu?
Schöner Artikel Chris, ich benutze das gerade für ein CodePen :-)
Was ist mit der Verwendung von
attr()in CSS, um Daten aus HTML zu erhalten, anstatt das hart zu kodieren?—
Nicht schlecht Subash, nicht schlecht.
Immer wenn ich Dinge austausche – auch einzelne Wörter – benutze ich nur JS, um Klassen zu wechseln
und CSS
Mehr Markup, weniger JS, aber fühlt sich besser an:)
Ja, mit
display: none;ist es eigentlich gar kein Problem mit der Barrierefreiheit, oder?Das ist, wie ich es vorziehe (normalerweise in einen Anker statt in ein Span gepackt). So kann ein Tastaturnutzer es auswählen, und der Screenreader liest immer vor, was es gerade sagt. Ändere die Klasse, und der Screenreader liest den neuen Text, wenn er zu dem Link zurückkehrt.
Die data-* Attribute auf Elementen können auch über element.dataset zugegriffen werden, so dass Sie Ihr "rohes" JavaScript-Beispiel auch so schreiben könnten
Natürlich funktioniert das nicht in IE < 11, aber wir können ja träumen :(
Anstatt sowohl den Originaltext als auch den Austauschtext in eigene data-Attribute zu speichern und eine if/else-Logik zu verwenden, um zu wählen, welcher angezeigt wird, könnten Sie einfach ein einziges data-Attribut verwenden, um den Text zu speichern, der gerade nicht angezeigt wird, und dann einfach die Werte tauschen. Weniger Markup erforderlich.
Peter, Sie haben bestätigt, was ich gerade überlegt habe. Ich stimme für die modifizierte Methode #1 :)
Definitiv besser. Außer dass es annimmt, dass das Ereignis den Text *immer* austauscht, egal was passiert, ohne den Zustand zu testen. Aber das ist sowieso so abstrakt, wenn wir "Was wäre wenn"-Szenarien betrachten, müssten wir viel komplizierter werden.
@Chris, richtig. Ich habe mich nur auf den Austausch von Text bezogen, da Ihr ursprüngliches Beispiel keine besonderen Bedingungen für den Austausch enthielt. Diese Logik könnte immer noch hinzugefügt werden, aber idealerweise hätten Sie wahrscheinlich eine separate Variable, um den "Zustand" zu identifizieren. Wenn Sie auf den Text des Buttons reagieren, fügen Sie Komplexität hinzu, wenn Sie jemals lokalisierten Text verwenden müssen.
Früher habe ich das mit Vanilla Javascript gemacht.
@Chris Nun, das ist nicht anders als bei den anderen Methoden, und die reine CSS-Methode kann nicht einmal besser als das: Ein/Aus, das ist alles.
Danke, Peter! Ich habe mir die ganze Zeit über dasselbe gedacht, während ich den Artikel gelesen habe. Das sollte die Standardmethode zum Umschalten sein.
Dennoch ein interessantes Thema. Ich habe mich oft gefragt, ob es etwas Einfacheres gibt, als es mit jQuery zu machen, und die Antwort scheint immer noch nein zu sein, wenn ich mir die CSS-Lösungen ansehe. Es gibt keinen Punkt, bei dem ich sagen würde: Ja, das ist viel sauberer und einfacher als es mit JS zu machen. :(
Etwas seltsam meiner Meinung nach – wir haben so viele schicke neue Elemente wie Video und spezielle Eingabefelder, aber immer noch kein einfaches Umschaltelement.
Hier ist die Vanilla-Version
Ich habe an dieselbe Lösung gedacht, die Peter Foti vorgeschlagen hat. Hier ist mein Fiddle.
http://jsfiddle.net/rnavaneethan/Fax7D/1/embedded/result/
Es wäre ein Overkill für dieses eher einfache Beispiel, aber da es Teil einer größeren Webanwendung ist, ist es wahrscheinlich, dass Sie bereits eines der vielen clientseitigen MV*-Frameworks verwenden. Unabhängig davon, ob Sie es manuell mit einer Ansicht in Backbone verdrahten oder ein Framework verwenden, das sie für Sie zusammenbindet (wie Ember oder Angular), ist es sauberer, den Zustand in einem Modell zu speichern.
Ich wollte nur sagen, dass in den ersten beiden JavaScript-Schnipseln eine schließende Klammer fehlt
Ich liebe Ihre Arbeit Chris. Eine mögliche Abkürzung für das JavaScript.
var button = document.querySelectorAll("button")[0]; // could be simplified with var button = document.querySelector("button");Ich schätze, er hat ursprünglich getElementsByTagName verwendet und es später aus irgendeinem Grund geändert, aber das ist kaum der Punkt.
Ich denke, wir können diese Zeile als "verwende die Methode, die für dich am besten passt, um dieses verdammte Button-Element zu bekommen!" lesen.
CSS zweiter Weg (französischer Touch)
input[type=checkbox].on-off{
appearance:none;
-webkit-appearance:none;
-moz-appearance:none;
}
input[type=checkbox].on-off:after{content:attr(data-unchecked);}
input[type=checkbox].on-off:checked:after{content:attr(data-checked);}
Schön, aber was ist das Französische daran?
Außerdem, wenn Sie sich sicher fühlen, :checked und appearance zu verwenden, sollten Sie auch ::after (Pseudoelement) anstelle von :after (Pseudoklasse) verwenden, da der einzige Grund, warum wir diese Syntax noch verwenden, IE8 ist...
Das ist der beste Weg, kein JS nötig mit reinem CSS, auch kein HTML-Code im CSS.
Das einzige, was ich hinzufügen werde, ist display: none für die Checkbox, weil appearance nicht in allen Browsern unterstützt wird.
Außerdem würde ich die Eingabe nicht in das Label legen, ansonsten ist das hier großartig.
<label><input class=”on-off” type=”checkbox” data-checked=”oui” data-unchecked=”non” /></label>
Vielleicht bin ich einfach komisch, aber normalerweise setze ich den Text zunächst in das HTML-Tag, das ich verwende, und wenn nötig, verwende ich jQuery, um den Inhalt dieses Textes durch den neuen Text zu ersetzen. So
$(“p”).text(“Ausblenden”);
und dann setze ihn zurück auf Anzeigen, wenn nötig
Gibt es einen Grund, warum das keine gute Idee ist?
Das liegt daran, dass Sie den Inhalt im DOM statt in Ihrem Code aufbewahren sollten. Um Dinge sauber und getrennt zu halten, wissen Sie.
Ihr Weg – der *traditionelle* Weg – ist definitiv einfacher, schneller und verbraucht weniger Speicher (aber wenn Sie sich um solche Dinge bei einer Aufgabe wie dieser sorgen, sollten Sie nicht einmal jQuery verwenden). Auf der anderen Seite, wenn das Projekt größer wird und Sie etwas ändern müssen, werden Sie Ihre Entscheidung vielleicht bereuen.
Stellen Sie sich vor, Sie haben *zwei* Umschalt-Buttons, aber beim zweiten sind die Wörter, die angezeigt werden müssen, zum Beispiel "Start" und "Stop": Sie müssen den Code für die gleiche Aufgabe noch einmal schreiben.
Wiederholen Sie dies *nach Belieben*, und Sie werden verstehen, worum es geht.
@Mike,
Wiederverwendbarkeit und Trennung von Belangen. Nehmen wir an, Sie haben zwei Buttons, die Textwerte umschalten, und einer schaltet zwischen Anzeigen/Ausblenden und der zweite zwischen Vorwärts/Rückwärts. Wenn Sie es auf Ihre Weise tun, müssen Sie für jeden zwei Sätze von JS schreiben und den View-Code (d. h. den angezeigten Text) in dem Code verwalten, der den Zustand (Ein/Aus) verwaltet.
Mit data-Attributen oder Ähnlichem muss Ihr JS nicht wissen, wie der Text lautet – nur den Zustand, und diesen Ein- oder Ausschalten.
Ich probiere die letzte reine CSS-Version in meinem Dreamweaver aus. Aber sie funktioniert nicht (Chrome, Firefox). Als ich dasselbe in Codepen gemacht habe, funktioniert es gut. Was habe ich verpasst?
CSS
#example { position: relative; } #example-checkbox { display: none; } #example-checkbox:checked + #example:after { content: "Hide"; position: absolute; top: 0; left: 0; right: 0; bottom: 0; background: white; }HTML
< input id=”example-checkbox” type=”checkbox”>
< label for=”example” id=”example”>Anzeigen < /label >
@Surjith
Das for-Attribut korrigiert
< label for=”example-checkbox” id=”example”>Anzeigen < /label >Danke Zet.
Es hat funktioniert.
Laut dem Beitrag ist auch ein Fehler.
http://jsfiddle.net/vmJ5h/
Ich mag die Art, wie Sie das Array für zwei Dinge verwendet haben :), clever
Können Sie mir den Array-Teil des Codes erklären: [ el.text(), el.text( el.data(‘swap’) ) ][0]
Der gesamte Ansatz hat keine if-else-Anweisungen und verwendet auch keine Variable, um den aktuellen Textwert zu speichern. Ich benutze zu diesem Zweck ein Array mit Länge=2. Das erste Element des Arrays ist der aktuelle Textwert. Das zweite Element tauscht tatsächlich den Textwert aus und verwendet den neuen Wert aus dem data-Attribut. Da wir den ursprünglichen Wert bereits als erstes Element im Array gespeichert haben, greifen wir sofort über [0] darauf zu. Und wir verwenden ihn, um den neuen Wert des data-Attributs zu setzen.
Keine "Ifs", keine Variablen, nur 2 Zeilen Code. Sauber & einfach.
Hallo, danke fürs Teilen. Ich verwende den reinen CSS-Weg in einem neuen Projekt, an dem ich gerade arbeite.
Übrigens, ich liebe Ihre Artikel und Tutorials. :)
Ich habe jQuery verwendet, aber meistens nur einfaches Vanilla...
Das Folgende kann direkt auf eine beliebige Anzahl von Elementen angewendet werden.
<button onclick=”elementStateChange(this, [“Anzeigen”,”Ausblenden”])”>Anzeigen</button>
function elementStateChange(which, display){
if (which.innerText == display[0]){
which.innerText =display[1] ;
}else{
which.innerText =display[0] ;
}
}
Anzeigen
Ups, das sollte herauskommen...
<script>
function elementStateChange(which, display){
if (which.innerText == display[0]){
}
</script>
<button onclick=’elementStateChange(this, [“Anzeigen”,”Ausblenden”])’>Anzeigen</button>
Nützliche Infos Chris.
@Paul
Noch kompakter
which.innerText = display[which.innerText == display[0] ? 1 : 0];
Der alte Weg (funktioniert von MS-IE4 / NN4 bis heute) ist
<input type=button value=Hide onclick="this.value = this.value == 'Hide' ? 'Show' : 'Hide';">
@Chris, @Peter
Der Zustand kann anhand dessen gesehen werden, was auf dem Button steht. Aber ich würde das nicht wirklich empfehlen, da Sie die Ansicht an den Zustand binden.
Ich habe eine Stimme im Hinterkopf, die sagt, das ist eine schlechte Idee, aber ein anderer Ansatz ist, zwei Buttons zu haben. Dieses HTML
Dieses CSS
#btn-show { display: none; }... und das folgende jQuery
$('.btn-show-or-hide').on( 'click', function () { $('.btn-show-or-hide').toggle(); });Gedanken?
Fiddle für oben: http://jsfiddle.net/davidg707/JNB2F/
Bezüglich des CSS-Wegs (mit jQuery, das Klassennamen ändert), könnten Sie text-indent verwenden und nicht mit einer Hintergrundfarbe überlagern und den Text darüber legen wie hier..
http://codepen.io/anon/pen/idmeG
Warum nicht einfach Klassen umschalten? Es gibt oft etwas HTML-Code. Data-Attr ist nicht immer genug.
Ich habe etwas Cooles mit CSS Generated Content in Opera (vor Chromium) bemerkt. Die
content-Eigenschaft funktioniert tatsächlich auf echten Elementen, nicht nur auf den Pseudoelementen vor und nach. Natürlich funktioniert das in keinem anderen Browser, und ich bin mir nicht einmal sicher, ob die Spezifikation dies vorsieht.Nur weil ich Ihre :after-Verwendung sehe, erinnere ich mich daran, alles. :)
Ich habe das gerade mit einer Mischung aus jQuery und Vanilla gemacht, indem ich eine Funktion erstellt habe, die beides übergibt, das Ziel, um den Zustand zu prüfen (da die meisten Textwechsel darauf basieren) und den Text zum Austauschen
und dann so aufrufen
und
Gedanken?
Wir müssen Daten in Variablen speichern, bevor wir sie austauschen.
Ich schlage vor, ein Element ohne Text im HTML zu verwenden
Und dieses JS, um es live zu machen
Ich habe dafür einen Pen erstellt: cdpn.io/yEJdw
nette Wege, ich mag den CSS-Weg, aber manchmal sind wir gezwungen, andere Wege zu gehen
Wie sorgt man dafür, dass das data-Attribut bei Seitenaktualisierung erhalten bleibt?