|
|
|
|
|
|
|||||||
| Tutorials Hier findest Du Tutorials, welche nach und nach ein fertiges Script ergeben. Sehen, lernen & verstehen! |
|
|
|
LinkBack (1) | Themen-Optionen | Thema bewerten |
|
|
#1 (permalink)
|
|
moderatives Dielektrikum
Registriert seit: 21.05.2008
Beiträge: 26.138
PHP-Kenntnisse: Fortgeschritten ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() |
Das nachfolgende Tutorial soll Euch anhand eines kleinen Beispiels die Verwendung von Javascript als behaviour layer näherbringen. Der Übersicht halber verzeiht mir bitte den aufs wesentliche reduzierten HTML Code. Zum Nachvollziehen bietet sich Firefox mit der Firebugerweiterung an, da sie auch nachträglich geänderte Attributwerte anzeigt.
Empfohlene Grundlagen
Aufgabenstellung Wir wollen als Beispiel ein einfaches Infofeld realisieren, das über ein Mausereignis an- und ausgeschaltet werden kann. Ein üblicher Ansatz wäre hier der folgende: toggleDiv.css: Code:
.switcher {background-color:#bbb;
margin:0; }
#Info {display:none;
background-color:#ff0;
height:3em;width:20em; }
Code:
toggleDivArea = function (sID)
{
oElement = document.getElementById (sID);
if (oElement.style.display=='none') oElement.style.display='block';
else oElement.style.display='none';
}
Code:
<html><head>
<link rel="stylesheet" type="text/css" href="toggleDiv.css" />
<script type="text/javascript" src="toggleDiv.js"></script>
</head><body>
<p class="switcher" onclick="toggleDivArea ('Info');">+ Schalter</p>
<div id="Info">Unser Infofeld</div>
</body></html>
Die gezeigte Lösung weist einige Schwächen auf, die wir nachfolgend sukzessive auflösen wollen:
Unser erklärtes Ziel Was mit CSS schon lange gang und gäbe ist, hält für Javascript erst langsam Einzug: die Abstraktion als eigene Ebene, den sogenannten 'behaviour layer'. Wie mit CSS die Formateigenschaften sollen über Attribute wie class und id mit Javascript funktionelle Eigenschaften definiert werden können. Unser obiges Beispiel könnte dann so aussehen: Code:
<html><head> <link rel="stylesheet" type="text/css" href="toggleDiv.css"> <script type="text/javascript" src="toggleDiv.js"></script> </head><body> <p class="switcher" tgg_target="Info">+ Schalter</p> <div id="Info">Unser Infofeld</div> </body></html> Schritt 1: Eine Grundlage Unser Ziel bietet schon mal die erste Hürde: JS stellt zwar die Funktionen getElementById, getElementsByName und getElementsByTagName bereit. Was wir jedoch gut gebrauchen könnten ist eine getElementsByClass Methode. Elements wohlgemerkt, denn das class Attribut kann und soll mehrfach vergeben werden. Und die bauen wir uns nun. Code:
getElementsByClass = function (sClassName)
{
var aReturnElements = [];
var oRegExpClass = new RegExp ('\\s*\\b' + sClassName + '\\b');
var oElements = (document.all)
? document.all
: document.getElementsByTagName ('*');
for (var i = 0 ; i < oElements.length ; i++)
{
if (oRegExpClass.test (oElements[i].className)) aReturnElements.push (oElements[i]);
}
return (aReturnElements);
}
Die Funktion ist übrigens eine abgeänderte Version von 'The Ultimate getElementsByClassName' [1], ist aber auch mannigfaltig anderswo im Netz zu finden. Schritt 2: Stil entwickeln Wir verabschieden uns von oElement.style.display='block' und abstrahieren. Wir führen statt dessen in unser bisheriges Stylesheet eine neue Formatklasse ein, die fortan von JS geschaltet wird. Für unser Beispiel reicht eine 'hidden' Klasse: toggleDiv.css: Code:
.switcher {background-color:#bbb;
margin:0; }
#Info {background-color:#ff0;
height:3em;width:20em; }
.hidden {display:none; }
An unserem HTML Code ändert sich nichts, JS muß jedoch angepaßt werden: toggleDiv.js: Code:
toggleDivArea = function (sID , iStatus)
{
oElement = document.getElementById (sID);
modifyClass (oElement , 'hidden');
}
modifyClass = function (oElement , sValue , iStatus)
{
var iStatus = iStatus || -1;
var oRegExpClass = new RegExp ('\\s*\\b' + sValue + '\\b');
if (-1 == iStatus) iStatus = ! oRegExpClass.test (oElement.className);
switch (iStatus)
{
case true :
case 1 :
case '1' :
oElement.className += ' ' + sValue;
break;
default:
oElement.className = oElement.className.replace (oRegExpClass , '');
break;
}
}
Anregungen zur Erweiterung:
Schritt 3: Simon befiehlt Unser Grundgerüst steht. Nun geht es um die Layerfunktionalität des JS Codes. Bisher wurde die Aktion ja durch das onclick Attribut im HTML Code des p tags eingeleitet. Dazu muß man wissen, dass jedes dieser Events in JS auch so gesetzt werden kann: Objektbezug.Event = Funktion; also z.B.: Code:
oElement.onclick = toggleDivArea; Code:
addToggleEvent = function (oElement)
{
var sTargetIdentifier = 'tgg_target';
var sTarget = oElement.getAttribute (sTargetIdentifier , false);
oElement.removeAttribute (sTargetIdentifier , false);
oElement.onclick = function ()
{
toggleDivArea (sTarget);
};
}
Da das noch nicht sehr komfortabel ist - schließlich muß ja vorher noch der Zugriff auf das Element erfolgen - erweitern wir unser JS um eine kleine Funktion, die diese Zuordnung einmalig für alle gewünschten Elemente übernimmt. Und hierbei kommt endlich unsere getElementsByClass Methode zum Einsatz. Wir werden unser Schalter-Element wahrscheinlich ohnehin später mit CSS formatieren, mit geeignetem Mauszeiger und einer Formatierung, die auf seine Funktion hinweist. Nichts liegt näher, als die dafür verwendete Klasse auch als Markierung für unsere JS Funktionalität einzusetzen. Es gilt also, alle Elemente mit der Klasseneigenschaft 'switcher' (siehe Ausgangsbeispiel) an die addToggleEvent Funktion zu übergeben. Und das geht so: Code:
addToggleEvents = function ()
{
var sMarkUp = 'switcher';
var oElements = getElementsByClass (sMarkUp);
var iLength = oElements.length;
for(var iCnt = 0 ; iCnt < iLength ; iCnt++)
{
addToggleEvent (oElements[iCnt]);
}
}
Code:
<html><head> <link rel="stylesheet" type="text/css" href="toggleDiv.css" /> <script type="text/javascript" src="toggleDiv.js"></script> </head><body> <p class="switcher" tgg_target="Info">+ Schalter</p> <div id="Info">Unser Infofeld</div> <script type="text/javascript"> addToggleEvents (); </script> </body></html> Anregungen zur Erweiterung:
Schritt 4: Viva Autonomia - Modularität Noch stört der Scriptaufruf am Ende. Schöner wäre doch, toggleDiv.js oben einzubinden und dabei schon automatisch die Toggle Funktion einzurichten. Das Problem ist dabei, dass alle Elemente bereits vorhanden sein müssen, die die onClick Event-Eigenschaft zugeordnet bekommen. Wir benötigen also einen Anstoß, wenn alle Elemente geladen sind. Genau das ermöglicht das window.onLoad Event. Eine Zeile in unserem toggleDiv.js genügt dafür: Code:
window.onload = addToggleEvents; Schritt 5: Keine Streitigkeiten am Tisch! Die nächste und für dieses Tutorial letzte Frage wirft Drew McLellan in seinem Artikel Writing Responsible JavaScript[2] auf: JS als Layer - wunderbar, aber was passiert, wenn unser Konzept window.onload = addToggleEvents; auch in anderen JS 'Modulen' verfolgt wird? Jede Zuweisung a´la window.onload = ... wird die alte überschreiben und schließlich wird nur die Funktionalität des zuletzt eingebundenen JS Layers übrig bleiben. Gottlob gibts auch dafür eine Lösung. Als - man könnte sagen - Quasistandard hat sich folgendes Fragment von Simon Willison[3] herausgebildet, das ich lediglich in meine Variablenschreibweise umgemünzt habe: Code:
addOnLoadEvent = function (mFunction)
{
var mOldOnLoad = window.onload;
if (typeof window.onload != 'function' )
{
window.onload = mFunction;
}
else
{
window.onload = function ()
{
if (mOldOnLoad) mOldOnLoad ();
mFunction ();
}
}
}
Das macht unser Modul komplett. Statt egoistisch window.onload = addToggleEvents; zu benutzen, geben wir auch anderen Modulen die Freiheit window.onload zu nutzen und ändern den Aufruf in addOnLoadEvent (addToggleEvents); ab. Resultat (erweitert um einige Spirenzien) Code:
<html><head> <link rel="stylesheet" type="text/css" href="toggleDiv.css" /> <script type="text/javascript" src="toggleDiv.js"></script> </head><body> <p class="switcher" tgg_target="Info">+ Schalter</p> <div id="Info">Unser Infofeld</div> </body></html> Code:
.switcher {background-color:#bbb;
margin:0; }
#Info {background-color:#ff0;
height:3em;width:20em; }
.hidden {display:none; }
Code:
// onLoad Event hinzufügen - Funktion sollte als Core Methode in ein
// separates externes JS
addOnLoadEvent = function (mFunction)
{
var mOldOnLoad = window.onload;
if (typeof window.onload != 'function' )
{
window.onload = mFunction;
}
else
{
window.onload = function ()
{
if (mOldOnLoad) mOldOnLoad ();
mFunction ();
}
}
}
// Zugriff auf DOM Element über Klasseneigenschft - Funktion sollte als Core
// Methode in ein separates externes JS
getElementsByClass = function (sClassName)
{
var aReturnElements = [];
var oRegExpClass = new RegExp ('\\s*\\b' + sClassName + '\\b');
var oElements = (document.all)
? document.all
: document.getElementsByTagName ('*');
for (var i = 0 ; i < oElements.length ; i++)
{
if (oRegExpClass.test (oElements[i].className)) aReturnElements.push (oElements[i]);
}
return (aReturnElements);
}
// Settings für die Umschaltfunktion
sTgg_DefaultMarkUpAttribute = 'switcher';
sTgg_DefaultTargetIdentifier = 'tgg_target';
sTgg_DefaultEvent = 'click';
toggleDivArea = function (sID , iStatus)
{
oElement = document.getElementById (sID);
modifyClass (oElement , 'hidden');
}
modifyClass = function (oElement , sValue , iStatus)
{
var iStatus = iStatus || -1;
var oRegExpClass = new RegExp ('\\s*\\b' + sValue + '\\b');
if (-1 == iStatus) iStatus = ! oRegExpClass.test (oElement.className);
switch (iStatus)
{
case true :
case 1 :
case '1' :
oElement.className += ' ' + sValue;
break;
default:
oElement.className = oElement.className.replace (oRegExpClass , '');
break;
}
}
addToggleEvent = function (oElement , sTargetIdentifier)
{
var sTargetIdentifier = sTargetIdentifier || sTgg_DefaultTargetIdentifier;
var sEvent = sTgg_DefaultEvent;
var sTarget = oElement.getAttribute (sTargetIdentifier , false);
oElement.removeAttribute (sTargetIdentifier , false);
if (oElement.addEventListener)
{
oElement.addEventListener (sEvent.toLowerCase() , function ()
{
toggleDivArea (sTarget);
} , false);
return (true);
}
else
if (oElement.attachEvent)
{
var mReturn = oElement.attachEvent('on' + sEvent.toLowerCase() , function ()
{
toggleDivArea (sTarget);
});
return (mReturn);
}
else
{
return (false);
}
}
addToggleEvents = function ()
{
var sMarkUp = sMarkUp || sTgg_DefaultMarkUpAttribute;
var oElements = getElementsByClass (sMarkUp);
var iLength = oElements.length;
for(var iCnt = 0 ; iCnt < iLength ; iCnt++)
{
addToggleEvent (oElements[iCnt]);
}
}
// Funktionalität des Moduls einbinden
addOnLoadEvent (addToggleEvents);
Quellen [1] http://www.robertnyman.com/2005/11/0...tsbyclassname/ [2] http://24ways.org/2006/writing-responsible-javascript [3] http://simonwillison.net/2004/May/26/addLoadEvent/ Und jetzt seid ihr dran... |
|
|
|
|
|
|
|
PHP Code Flüsterer
Registriert seit: 21.08.2005
Beiträge: 4682
PHP-Kenntnisse:
Fortgeschritten
|
|
|
|
#2 (permalink) |
|
moderatives Dielektrikum
Registriert seit: 21.05.2008
Beiträge: 26.138
PHP-Kenntnisse: Fortgeschritten ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() |
Nachgereicht - das verbesserte addToggleEvent
Im obigen Scripting zum Resultat wurde addToggleEvent im Vergleich zu den vorhergehenden Ausführungen stark verändert. Was dort veranstaltet wurde ähnelt dem Ziel, das wir schon für window.onload verfolgt haben: wie in addOnLoadEvent wurde hier allgemeingültig das mit sEvent bezeichnete Ereignis um eine weitere Funktion ergänzt, statt es einfach zu überschreiben. Die relativ aufwendige if Struktur dient - wie immer - der Befriedigung verschiedener Browser-Herangehensweisen an die Problemstellung; addEventListener bildet hier die von DOM Level 2 angebotene Zugriffsmethode, während der IE mittels attachEvent arbeitet. Die ganze Funktion entstand dann quasi aus einer Kombination aus der Funktionskapselung der addOnLoadEvent Methode und einem von Ulrike Häßler vorgestellten Scriptfragment 'javascript: Event Listener' [4]. Schritt 6: Eventzuweisung aufgebohrt Wenn man das eingangs beschrieben Modulkonzept für JS verwirklichen möchte, lässt sich schnell erkennen, dass die in addToggleEvent implementierte Verfahrensweise doch ruck zuck zu einem großen Overhead führt. Deshalb wollen wir hier noch einmal die Schere ansetzen und uns eine allgemeingültige Methode zum Erweitern der Eventeigenschaften eines Objektes schaffen. Hier können wir uns fast auf copy and paste beschränken: Unsere Funktion benötigt drei Parameter, eine Referenz auf das Objekt, den Bezeichner des einzurichtenden Events und die dabei auszuführende Funktion. Code:
addEvent = function (oElement , sEvent , oFunction)
{
if (oElement.addEventListener)
{
oElement.addEventListener (sEvent.toLowerCase() , function ()
{
oFunction ();
} , false);
return (true);
}
else
if (oElement.attachEvent)
{
var mReturn = oElement.attachEvent('on' + sEvent.toLowerCase() , function ()
{
oFunction ();
});
return (mReturn);
}
else
{
return (false);
}
}
Eine Zuweisungsoperation sparen wir uns beim Aufruf, vielmehr schreiben wir gleich die gesamte Funktion als Parameter in addEvent's Parameterkette. Beispielhaft für addToggleEvent: Code:
addToggleEvent = function (oElement , sTargetIdentifier)
{
var sTargetIdentifier = sTargetIdentifier || sTgg_DefaultTargetIdentifier;
var sEvent = sTgg_DefaultEvent;
var sTarget = oElement.getAttribute (sTargetIdentifier , false);
oElement.removeAttribute (sTargetIdentifier , false);
addEvent (oElement , sEvent , function ()
{
toggleDivArea (sTarget);
});
}
Bis jetzt klappt alles wunderbar. An die Grenzen stoßen wir, wenn wir das aktuell aufgetretene Eventobjekt auswerten möchten. Das wird dann notwendig, wenn wir auf bestimmte Tastaturereignisse reagieren wollen oder Mousekoordinaten ermitteln. Das Eventobjekt wird von JS wie von Zauberhand automatisch als Funktionsparameter übergeben. Das wirkt auf mich bis heute auch noch recht befremdlich. So kann ich ein per Code:
oElement.onmousedown = trackMouse; Code:
trackMouse = function (oEvent)
{
// non IE only
alert (oEvent.layerX);
}
Glücklicherweise haben wir uns ja ohnehin für die oben beschriebene Auslagerung der Eventzuweisung entschieden und können dieses Problem so lösen: Code:
addEvent (oElement , 'mousedown' , function (oEvent) { trackMouse (oEvent , 'my Parameter'); });
Code:
addEvent = function (oElement , sEvent , oFunction)
{
if (oElement.addEventListener)
{
oElement.addEventListener (sEvent.toLowerCase() , function (oEvent)
{
oFunction (oEvent);
} , false);
return (true);
}
else
if (oElement.attachEvent)
{
var mReturn = oElement.attachEvent('on' + sEvent.toLowerCase() , function (oEvent)
{
oFunction (oEvent);
});
return (mReturn);
}
else
{
return (false);
}
}
Quellen [4] http://www.mediaevent.de/javascript/event_listener.html . |
|
|
|
|
|
#5 (permalink) |
|
Erfahrener Benutzer
Registriert seit: 06.06.2008
Beiträge: 1.624
PHP-Kenntnisse: Anfänger ![]() |
Damit man versteht was da eigentlich passiert.
Ich muss zugegeben, dass ich mit Developer Version nicht allzu viel anfangen kann. Viele Zusammenhänge erschließen mir sich einfach nicht. Und Code:
if (Statement)
Expression;
__________________
"Nobody is as smart as everybody" - Kevin Kelly — The best things in life aren't things |
|
|
|
|
| Themen-Optionen | |
| Thema bewerten | |
|
|
LinkBacks (?)
LinkBack to this Thread: http://www.php.de/tutorials/44167-js-einfuehrung-javascript-im-schichtenmodell.html
|
||||
| Erstellt von | For | Type | Datum | |
| OpenWebBoard / Tutorials / JavaScript / Query-Syntax nachr | This thread | Refback | 02.11.2008 19:30 | |
Ähnliche Themen
|
||||
| Thema | Autor | Forum | Antworten | Letzter Beitrag |
| Lange Verarbeitungszeiten - Zuviel JavaScript? | [-UFO-]Melkor | HTML, Usability und Barrierefreiheit | 2 | 15.06.2007 23:54 |
| http user mit Javascript abfrage | tennessee | HTML, Usability und Barrierefreiheit | 3 | 31.10.2006 13:18 |
| Unsichtbares Formularfeld mit Javascript ansprechen | mAy^daY | HTML, Usability und Barrierefreiheit | 6 | 13.08.2006 21:25 |
| PHP + Javascript + MYSQL | socke | PHP Tipps 2006 | 4 | 02.04.2006 22:02 |
| Ist JavaScript OOP sinnvoll? | HStev | HTML, Usability und Barrierefreiheit | 2 | 26.01.2006 12:11 |
| Variable wird geändert bei Übergabe an Javascript | PHP Tipps 2007 | 4 | 17.12.2005 16:53 | |
| 2 javascript fragen | Rotti | HTML, Usability und Barrierefreiheit | 4 | 03.08.2005 11:40 |
| Mit PHP prüfen ob JavaScript beim Browser aktiviert ist? | HTML, Usability und Barrierefreiheit | 3 | 21.07.2005 12:43 | |
| Php soll Javascript beschleunigen | PHP Tipps 2005 | 4 | 17.04.2005 12:56 | |
| Javascript ON/OFF | Connar | PHP Tipps 2005 | 3 | 03.04.2005 09:47 |
| [Erledigt] JavaScript +mehrereFenster | HTML, Usability und Barrierefreiheit | 5 | 03.02.2005 15:08 | |
| Formulare mit arrays mit php und gleichzeitig mit JavaScript | PHP-Fortgeschrittene | 2 | 14.10.2004 15:33 | |
| JavaScript in JavaScript geschriebene Html-Datei einbinden. | woods | HTML, Usability und Barrierefreiheit | 6 | 06.09.2004 18:33 |
| Javascript | HTML, Usability und Barrierefreiheit | 5 | 31.08.2004 18:30 | |
| php + Javascript, Variablenübergabe | PHP Tipps 2004 | 14 | 28.07.2004 15:42 | |

Dieser Inhalt ist unter einer Creative Commons-Lizenz lizenziert.