diff --git a/css.html b/css.html index 288e4d9..86e63f2 100644 --- a/css.html +++ b/css.html @@ -43,9 +43,9 @@

Stylesheet-Regeln auf ein Element anwenden

Betrachten wir als Beispiel ein JavaScript, dass die Eingaben eines Formulars überprüft. Beim Absenden des Formulars wird eine Handler-Funktion für das Ereignis submit aktiv. Diese Funktion soll fehlerhafte Formularfelder rot markieren.

Nehmen wir an, die input-Eingabefelder sind standardmäßig im Stylesheet so formatiert:

input {
-   padding: 4px 6px;
-   border: 1px solid #555;
-   background-color: #fafafa;
+    padding: 4px 6px;
+    border: 1px solid #555;
+    background-color: #fafafa;
 }

Im Stylesheet wird nun eine Regel definiert mit den Eigenschaften für fehlerhafte Felder. Wir nutzen dazu einen Selektor mit dem Elementnamen input kombiniert mit der Klasse fehlerhaft:

input.fehlerhaft {
@@ -58,43 +58,43 @@ 

Stylesheet-Regeln auf ein Element anwenden

element.className = 'klassenname';

In der beispielhaften Formularüberprüfung kann das Setzen der Klasse folgendermaßen aussehen: Wir definieren eine Funktion formularÜberprüfung, die als Handler für das Ereignis submit registriert wird (siehe Ereignisverarbeitung). In dieser Funktion wird das zu überprüfende Formularfeld über das DOM mittels document.getElementById herausgesucht. Ist der Wert des Feldes leer, wird eine Meldung ausgegeben und das Feld bekommt die Klasse fehlerhaft.

function formularÜberprüfung () {
-   // Spreche das Formularfeld über das DOM an und
-   // speichere es in eine Variable zwischen:
-   var element = document.getElementById("kontaktformular-name");
-   // Prüfe den Feldwert:
-   if (element.value == "") {
-      // Zeige im Fehlerfall ein Hinweisfenster:
-      window.alert("Bitte geben Sie Ihren Namen an.");
-      // Weise dem Element die Klasse »fehlerhaft« zu:
-      element.className = 'fehlerhaft';
-      // Setze den Fokus auf das Feld:
-      element.focus();
-      // Verhindere das Absenden des Formulars
-      // (unterdrücke die Standardaktion des Ereignisses):
-      return false;
-   }
+    // Spreche das Formularfeld über das DOM an und
+    // speichere es in eine Variable zwischen:
+    var element = document.getElementById("kontaktformular-name");
+    // Prüfe den Feldwert:
+    if (element.value == "") {
+        // Zeige im Fehlerfall ein Hinweisfenster:
+        window.alert("Bitte geben Sie Ihren Namen an.");
+        // Weise dem Element die Klasse »fehlerhaft« zu:
+        element.className = 'fehlerhaft';
+        // Setze den Fokus auf das Feld:
+        element.focus();
+        // Verhindere das Absenden des Formulars
+        // (unterdrücke die Standardaktion des Ereignisses):
+        return false;
+    }
 }
 
 function init () {
-	// Starte die Ereignis-Überwachung mittels
-	// traditionellem Event-Handling
-	document.getElementById("kontaktformular").onsubmit = formularÜberprüfung;
+    // Starte die Ereignis-Überwachung mittels
+    // traditionellem Event-Handling
+    document.getElementById("kontaktformular").onsubmit = formularÜberprüfung;
 }
 
 window.onload = init;

Der zugehörige HTML mit den nötigen IDs könnte so aussehen:

<form action="…" method="post" id="kontaktformular">
-   <p><label>
-      Ihr Name:
-      <input type="text" name="name" id="kontaktformular-name">
-   </label></p>
-   … weitere Felder …
-   <p><input type="submit" value="Absenden"></p>
+    <p><label>
+        Ihr Name:
+        <input type="text" name="name" id="kontaktformular-name">
+    </label></p>
+    … weitere Felder …
+    <p><input type="submit" value="Absenden"></p>
 </form>
 

Der Clou dieser Vorgehensweise ist, dass Sie mit dem Setzen der Klasse an einem Element nur eine minimale JavaScript-Änderung vornehmen. Diese Änderung führt dazu, dass eine Regel aus dem Stylesheet plötzlich auf bestimmte Elemente greift – der Browser wendet daraufhin automatisch die definierten Formatierungen an.

Über dieses Modell können Sie auch komplexere Aufgabenstellungen lösen, denn Ihnen stehen alle Möglichkeiten von CSS-Selektoren zu Verfügung. Beispielsweise können Sie mittels Nachfahrenselektoren Elemente formatieren, die unterhalb des mit der Klasse markierten Elements liegen. So können Sie durch die Änderung der Klasse gleich mehrere enthaltene, im DOM-Baum unterhalb liegende Elemente formatieren, ohne diese einzeln anzusprechen.

-

TODO: Beispiel dazu

+

TODO: Beispiel dazu. Mit Nachfahrenselektoren größere Umformatierungen vornehmen, ohne alle Elemente einzeln anzusprechen

Komfortables Hinzufügen, Löschen und Abfragen von Klassen

Die oben vorgestellte Methode zum Setzen der Klasse ist stark vereinfacht und hat verschiedene Nachteile. Ein HTML-Element kann nämlich mehreren Klassen angehören. Die JavaScript-Eigenschaft className enthält dann eine Liste von Klassen, die durch Leerzeichen getrennt werden.

@@ -108,37 +108,37 @@

Komfortables Hinzufügen, Löschen und Abfragen von Klassen

Falls Sie keine Fertigbibliothek nutzen, können Sie diese Helferfunktionen dennoch in ihre Scripte aufnehmen. Eine mögliche Umsetzung als lose globale Funktionen sieht folgendermaßen aus:

function addClass (element, className) {
-	if (!hasClass(element, className)) {
-		if (element.className) {
-			element.className += " " + className;
-		} else {
-			element.className = className;
-		}
-	}
+    if (!hasClass(element, className)) {
+        if (element.className) {
+            element.className += " " + className;
+        } else {
+            element.className = className;
+        }
+    }
 }
 
 function removeClass (element, className) {
-	var regexp = addClass[className];
-	if (!regexp) {
-		regexp = addClass[className] = new RegExp("(^|\\s)" + className + "(\\s|$)");
-	}
-	element.className = element.className.replace(regexp, "$2");
+var regexp = addClass[className];
+    if (!regexp) {
+        regexp = addClass[className] = new RegExp("(^|\\s)" + className + "(\\s|$)");
+    }
+    element.className = element.className.replace(regexp, "$2");
 }
 
 function hasClass (element, className) {
-	var regexp = addClass[className];
-	if (!regexp) {
-		regexp = addClass[className] = new RegExp("(^|\\s)" + className + "(\\s|$)");
-	}
-	return regexp.test(element.className);
+    var regexp = addClass[className];
+    if (!regexp) {
+        regexp = addClass[className] = new RegExp("(^|\\s)" + className + "(\\s|$)");
+    }
+    return regexp.test(element.className);
 }
 
 function toggleClass (element, className) {
-	if (element.hasClass(className)) {
-		element.removeClass(className);
-	} else {
-		element.addClass(className);
-	}
+    if (element.hasClass(className)) {
+        element.removeClass(className);
+    } else {
+        element.addClass(className);
+    }
 }

Alle Funktionen erwarten jeweils zwei Parameter, nämlich das Elementobjekt und den gewünschten Klassennamen als String. Folgende Beispiele sollen die Anwendung illustrieren:

// Element ansprechen und Elementobjekt in einer Variable zwischenspeichern:
@@ -151,9 +151,9 @@ 

Komfortables Hinzufügen, Löschen und Abfragen von Klassen

toggleClass(element, "beispielklasse"); // Vorhandensein einer Klasse prüfen: if (hasClass(element, "beispielklasse")) { - window.alert("Klasse gefunden."); + window.alert("Klasse gefunden."); } else { - window.alert("Klasse nicht gefunden."); + window.alert("Klasse nicht gefunden."); }

Mit diesen Funktionen in Ihrem JavaScript-Werkzeugkasten können Sie das Zusammenspiel von JavaScript-Interaktivität und Stylesheet-Formatierungen komfortabel und übersichtlich meistern.

@@ -174,7 +174,7 @@

Das style-Objekt als Schnittstelle zu Inline-Styles

document.getElementById("beispielID").style.backgroundColor = "red";

Als Werte müssen Sie stets Strings angeben genau in der Form, wie sie in CSS spezifiziert sind. Das gilt auch für Zahlenwerte, die eine Einheit erfordern:

element.style.marginTop = 15; // Falsch!
-	element.style.marginTop = "15px"; // Richtig
+element.style.marginTop = "15px"; // Richtig

Sonderfälle bei der Umsetzung von CSS- in JavaScript-Eigenschaftsnamen

@@ -193,11 +193,11 @@

style ist nicht zum Auslesen der gegenwärtigen Eigenschaftswer <p id="mit-inline-styles" style="color: red">Element mit Inline-Styles</p>
// Gibt einen leeren String aus:
 window.alert(
-	document.getElementById("ohne-inline-styles").style.backgroundColor
+    document.getElementById("ohne-inline-styles").style.backgroundColor
 );
 // Gibt »red« aus, weil Inline-Style gesetzt wurde:
 window.alert(
-	document.getElementById("mit-inline-styles").style.backgroundColor
+    document.getElementById("mit-inline-styles").style.backgroundColor
 );

@@ -223,20 +223,20 @@

Microsofts currentStyle

var currentStyle = element.currentStyle; window.alert("Textfarbe: " + currentStyle.color); window.alert("Elementbreite: " + currentStyle.width); -

currentStyle liefert meist ein ähnliches Ergebnis wie das standardisierte getComputedStyle. In manchen Fällen gibt es jedoch Abweichungen, etwa im obigen Beispiel beim Auslesen des width-Wertes. Der Internet Explorer gibt auto zurück, wenn dem Element keine explizite Breite zugewiesen wurde. Für das browserübergreifende Auslesen der Box-Größe eignen sich stattdessen die Eigenschaoffset client

+

currentStyle liefert meist ein ähnliches Ergebnis wie das standardisierte getComputedStyle. In manchen Fällen gibt es jedoch Abweichungen, etwa im obigen Beispiel beim Auslesen des width-Wertes. Der Internet Explorer gibt auto zurück, wenn dem Element keine explizite Breite zugewiesen wurde. Für das browserübergreifende Auslesen der Box-Größe eignen sich stattdessen die Eigenschaft offsetWidth/offsetHeight sowie clientWidth/clientHeight.

Browserübergreifendes Auslesen von CSS-Eigenschaften

Durch Kombination von getComputedStyle für standardkonforme Browser und currentStyle für den Internet Explorer können wir eine lose Helferfunktion schreiben, die uns den aktuellen CSS-Eigenschaftswert liefert. Die Funktion fragt ab, welches Objekt zur Verfügung steht, und bringt den Wert damit in Erfahrung:

function getStyleValue (element, cssProperty) {
-	var value = "";
-	if (window.getComputedStyle) {
-		value = window.getComputedStyle(element, null)[cssProperty];
-	} else if (element.currentStyle) {
-		value = element.currentStyle[cssProperty];
-	}
-	return value;
+    var value = "";
+    if (window.getComputedStyle) {
+        value = window.getComputedStyle(element, null)[cssProperty];
+    } else if (element.currentStyle) {
+        value = element.currentStyle[cssProperty];
+    }
+    return value;
 }

Bei der Anwendung wird der Funktion das Elementobjekt und ein String übergeben, der den Eigenschaftsnamen in der JavaScript-typischen Schreibweise enthält:

var currentFontSize = getStyleValue(document.getElementById("beispielID"), "fontSize");
@@ -247,21 +247,19 @@ 

Browserübergreifendes Auslesen von CSS-Eigenschaften

Elementbox-Größen auslesen über Microsoft-Eigenschaften

-

Über die vorgestellten Techniken ist es nicht browserübergreifend möglich, die aktuelle Höhe und Breite einer Element-Box auszulesen. Stattdessen sollten Sie folgende Eigenschaften der Elementobjekte verwenden. Sie wurden ursprünglich von Microsoft erfunden, erfreuen sich aber breiter Browser-Unterstützung. Im Gegensatz zu getComputedStyle und currentStyle geben sie keine String-Werte samt Einheiten zurück, sondern direkt JavaScript-Zahlen (Number-Wert).

+

Über die vorgestellten Techniken ist es nicht browserübergreifend möglich, die aktuelle Höhe und Breite einer Element-Box in der Einheit Pixel auszulesen. Stattdessen sollten Sie folgende Eigenschaften der Elementobjekte verwenden. Sie wurden ursprünglich von Microsoft erfunden, erfreuen sich aber breiter Browser-Unterstützung. Im Gegensatz zu getComputedStyle und currentStyle geben sie keine String-Werte samt Einheiten zurück, sondern direkt JavaScript-Zahlen (Number-Werte) in der Einheit Pixel.

offsetWidth und offsetHeight
-
liefern die Breite bzw. Höhe der border box (Rahmen-Box) des Elements. Das bedeutet, dass padding (Innenabstand) und border (Rahmen) inbegriffen sind, margin (Außenrahmen) hingegen nicht.
+
liefern die Breite bzw. Höhe der Rahmen-Box des Elements. Das bedeutet, dass der Innenabstand (padding) und der Rahmen (border) inbegriffen sind, der Außenrahmen hingegen (margin) nicht.
clientWidth und clientHeight
-
liefern Breite bzw. Höhe der padding box (Innenabstand-Box) des Elements. Das bedeutet, dass padding inbegriffen ist, während border und margin nicht eingerechnet werden. Ebenso wird eine möglicherweise angezeigte Bildlaufleiste (Scrollbar) nicht einberechnet.
-
clientWidth und clientHeight
-
liefern die innere Breite bzw. Höhe des Elements. margin, border, padding sowie die Größe der Bildlaufleiste werden nicht einberechnet.
+
liefern Breite bzw. Höhe der Innenabstand-Box des Elements. Das bedeutet, dass padding inbegriffen ist, während border und margin nicht eingerechnet werden. Ebenso wird die Größe einer möglicherweise angezeigte Bildlaufleiste (Scrollbar) nicht einberechnet.
scrollWidth und scrollHeight
-
geben die tatsächliche Höhe des Inhalts wieder, wenn das Element kleiner ist, als der Inhalt es erfordert, und das Element Bildlaufleisten besitzt, um diesen Inhalt zugänglich zu machen. Die vorher genannten Eigenschaften geben in diesem Fall lediglich die Größe des »Guckfensters«, also des aktuell sichtbaren Ausschnittes wieder.
+
geben die tatsächlich angezeigte Breite bzw. Höhe des Inhalts wieder. Wenn das Element kleiner ist, als der Inhalt es erfordert, also Bildlaufleisten angezeigt werden, so geben diese Eigenschaften die Größe des des aktuell sichtbaren Ausschnittes wieder.

In den meisten Fällen werden Sie die äußere Größe eines Elements benötigen, also offsetWidth und offsetHeight. Das folgende Beispiel gibt die Größe eines Elements aus:

var element = document.getElementById('beispielID');
 window.alert("Breite: " + element.offsetWidth + "\nHöhe: " + element.offsetHeight);
-

TODO: Das ist die Theorie, Browser-Unstimmigkeiten sind bei Quirksmode dokumentiert

+

Falls sie die innere Größe benötigen, so können Sie zunächst die aktuellen Werte der jeweiligen padding-Eigenschaften auslesen. Das sind padding-left und padding-right für die Breite bzw. padding-top und padding-bottom für die Höhe. Diese substrahieren sie von offsetWidth bzw. offsetHeight, um die tatsächliche Innengröße zu erhalten.

diff --git a/organisation-instanzen.html b/organisation-instanzen.html index fc69ac4..301839c 100644 --- a/organisation-instanzen.html +++ b/organisation-instanzen.html @@ -111,25 +111,8 @@

Prototypische Objekte (Prototypen)

mauzi.miau(); -

Hier wird Funktionausdruck notiert und die Funktion in Katze.prototype.miau gespeichert. Beim Prototypen wird also eine Eigenschaft namens miau angelegt. Darin steckt nun die neu angelegte Funktion. Wenn wir eine Katze-Instanz erzeugen, so besitzt sie eine miau-Methode.

+

Hier wird ein Funktionausdruck notiert und das Funktionsobjekt in Katze.prototype.miau gespeichert. Beim Prototypen wird also eine Eigenschaft namens miau angelegt. Darin steckt nun die neu angelegte Funktion. Wenn wir eine Katze-Instanz erzeugen, so besitzt sie eine miau-Methode.

-

Eine gleichwertige Alternativschreibweise ersetzt das Prototyp-Objekt mit einem eigenen Objekt. Dieses kann z.B. mit einem Object-Literal notiert werden. Wenn dem Prototypen viele Eigenschaften angehängt werden, ist diese Schreibweise letztlich kürzer, als mehrfach Katze.prototype.eigenschaft = ... zu schreiben.

- -
-function Katze () {}
-
-Katze.prototype = {
-    miau : function () {
-        alert("Miau!");
-    }
-};
-
-var maunzi = new Katze();
-mauzi.miau();
-
- -

Mit dem Object-Literal wird ein Objekt angelegt, welches eine miau-Methode besitzt. Durch die Zuweisung an Katze.prototype wird dieses Objekt wird zum Prototypen für alle Katze-Instanzen.

-
@@ -233,13 +216,12 @@

Prototypen verstehen: Die Glasplatten-Metapher

Diese Art der Vererbung nennt man Differential Inheritance. Im Gegensatz zur klassenbasierten Vererbung werden beim abgeleiteten Objekt (der Instanz) keine Eigenschaften erzeugt. Die Instanz ist keine Kopie des Prototypen, die Instanz kann sogar leer sein, wie es Katzen-Beispiel der Fall ist. Erst wenn sich die Instanz vom Prototypen unterscheidet, wird bei der Instanz eine Eigenschaft angelegt, die einen anderen Wert als die des Prototypen besitzt. In der Glasplatten-Metapher bedeutet dies: An den Stellen, in denen die Instanz dem Prototyp gleicht, ist die Platte durchsichtig – sie delegiert . Wo sie sich unterscheidet, besitzt sie einen eigenen, andersfarbigen Zettel.

-

Nehmen wir an, dass hiesige Katzen meistens von der Rasse »Europäisch Kurzhaar« sind. Anstatt dies jedes Mal beim Erzeugen anzugeben, notieren wir die Eigenschaft im Prototypen:

+

Nehmen wir an, dass hiesige Katzen meistens von der Rasse »Europäisch Kurzhaar« sind. Anstatt dies jedes Mal beim Erzeugen anzugeben, legen wir die Eigenschaft beim Prototypen an:

 function Katze () {}
-Katze.prototype = {
-    rasse : "Europäisch Kurzhaar"
-};
+Katze.prototype.rasse = "Europäisch Kurzhaar";
+
 var maunzi = new Katze();
 alert(maunzi.rasse);
 
@@ -272,6 +254,7 @@

Katze.prototype

 var maunzi = new Katze();
 alert(maunzi.rasse); // Derzeit noch »Europäisch Kurzhaar« - vererbt vom Prototypen
+
 maunzi.rasse = "Perser";
 alert(maunzi.rasse); // Jetzt »Perser« - eigene Eigenschaft
 
@@ -313,11 +296,9 @@

Private Objekte anstatt private Eigenschaften

 function Katze () {}
 
-Katze.prototype = {
-    pfoten : 4,
-    miau : function () {
-        alert("Miau!");
-    }
+Katze.prototype.pfoten = 4;
+Katze.prototype.miau = function () {
+   alert("Miau!");
 };
 
 var maunzi = new Katze();
@@ -330,7 +311,7 @@ 

Private Objekte anstatt private Eigenschaften

// Überschreibe Methode des Prototyps: Katze.prototype.miau = function () { - alert("Wau, wau!"); + alert("Wau, wau!"); }; schnucki.miau();
@@ -496,17 +477,17 @@

Pseudo-private Objekte

 function Konstruktor () {}
-Konstruktor.prototype = {
-    // Öffentliche Eigenschaften
-    öffentlicheMethode : function () {
-        alert(this._privateMethode());
-    },
-    // Pseudo-private Eigenschaften
-    _privateEigenschaft : 1;
-    _privateMethode : function () {
-        this._privateEigenschaft++;
-        return this._privateEigenschaft;
-    }
+
+// Öffentliche Eigenschaften
+Konstruktor.prototype.öffentlicheMethode = function () {
+   alert(this._privateMethode());
+};
+
+// Pseudo-private Eigenschaften
+Konstruktor.prototype._privateEigenschaft = 1;
+Konstruktor.prototype._privateMethode = function () {
+   this._privateEigenschaft++;
+   return this._privateEigenschaft;
 };
 
 var instanz = new Konstruktor();
diff --git a/organisation-ueberblick.html b/organisation-ueberblick.html
index ccceb16..13f01d1 100644
--- a/organisation-ueberblick.html
+++ b/organisation-ueberblick.html
@@ -80,7 +80,7 @@ 

Scripte bei DOM Ready initialisieren

 $(document).ready(function () {
-	// Diese Funktion wird beim DOM ready ausgeführt
+    // Diese Funktion wird beim DOM ready ausgeführt
 });
 
@@ -88,7 +88,7 @@

Scripte bei DOM Ready initialisieren

 $(function () {
-	// ...
+    // ...
 });
 
@@ -110,8 +110,8 @@

DOM-Zugriffe über Selektor-Engines

 $(document).ready(function () {
-	// Liefert alle li-Elemente im Element mit der ID produktliste
-	$('#produktliste li')
+    // Liefert alle li-Elemente im Element mit der ID produktliste
+    $('#produktliste li')
 });
 
@@ -127,9 +127,9 @@

Zeitgemäßes Event-Handling

 $(document).ready(function () {
-	$('#produktliste li').click(function (e) {
-		// ... Verarbeite Ereignis ...
-	});
+    $('#produktliste li').click(function (e) {
+        // ... Verarbeite Ereignis ...
+    });
 });