Elemente in Variablen
Olli
- javascript
Hallo.
function fooBar() {
var foo = document.getElementById('bar');
foo.setAttribute...
foo...
foo...
}
Innerhalb einer Funktion ist das wohl durchaus sinnvoll (Lesbarkeit und Performance).
Wenn das Element document.getElementById('bar') nun in vielen Funktionen verwendet wird, ist es dann auch sinnvoll dieses Element in eine globale Variable abzuspeichern und dann aus den Funktionen auf diese zuzugreifen?
Olli
Hi,
function fooBar() {
var foo = document.getElementById('bar');
foo.setAttribute...
foo...
foo...
}Innerhalb einer Funktion ist das wohl durchaus sinnvoll (Lesbarkeit und Performance).
nein, den Umweg über setAttribute() solltest du dir zugunsten eines direkten Zugriffs auf die jeweiligen Eigenschaften sparen. Statt
foo.setAttribute("id", ...);
also bevorzugt:
foo.id = ... ;
Das ist erstens besser lesbar, zweitens zickt der IE mit setAttribute() gern mal rum, wenn das Attribut auch auf dem direkten Weg gesetzt werden könnte.
Wenn das Element document.getElementById('bar') nun in vielen Funktionen verwendet wird, ist es dann auch sinnvoll dieses Element in eine globale Variable abzuspeichern und dann aus den Funktionen auf diese zuzugreifen?
Ja. Anstatt jedesmal das DOM zu durchsuchen, ist es tatsächlich effizienter, die Referenz auf das gesuchte Objekt einmal zu ermitteln und dann zu speichern. Ob eine globale Variable dafür die beste Strategie ist, sei dahingestellt; man könnte diese Information auch einem nahegelegenen Objekt als zusätzliche Eigenschaft anhängen.
So long,
Martin
zweitens zickt der IE mit setAttribute() gern mal rum, wenn das Attribut auch auf dem direkten Weg gesetzt werden könnte.
Das stimmt. Allerdings geht das bei z.B. style nicht direkt.
Ja. ...
Danke.
zweitens zickt der IE mit setAttribute() gern mal rum, wenn das Attribut auch auf dem direkten Weg gesetzt werden könnte.
Das stimmt. Allerdings geht das bei z.B. style nicht direkt.
Doch wieso sollte es nicht gehen?
obj.style.color = 'red';
Struppi.
Doch wieso sollte es nicht gehen?
Mein Fehler.
Hallo,
zweitens zickt der IE mit setAttribute() gern mal rum, wenn das Attribut auch auf dem direkten Weg gesetzt werden könnte.
Das stimmt. Allerdings geht das bei z.B. style nicht direkt.
das wäre mir aber neu. Dann muss ich wohl geträumt haben, wenn ich das bisher so gemacht habe.
Ciao,
Martin
gruss Olli,
function fooBar() {
var foo = document.getElementById('bar');
foo.setAttribute...
foo...
foo...
}Wenn das Element document.getElementById('bar') nun in vielen Funktionen
verwendet wird, ist es dann auch sinnvoll dieses Element in eine globale
Variable abzuspeichern und dann aus den Funktionen auf diese zuzugreifen?
es gehoert mittlerweile zum guten stil, den globalen namensraum nicht
zu verschmutzen.
anwendungen sollten daher auf das u.a von YAHOO detailiert beschriebene
JavaScript "module pattern" aufbauen.
beispielcode:
(function () { // "anonymer namensraum"
var elmBar;
var fooBar = (function () {/*
elmBar.setAttribute ...
elmBar. ...
elmBar. ...*/
});
var initialize = (function () {
elmBar = document.getElementById("bar");
});/*
wenn moeglich auf DOM-ready mit der bibliothek Deiner wahl - pseudocode:
*/
$(document).ready(initialize);
})();
so long - peterS. - pseliger@gmx.net
Hallo peterS,
Da du gerade wieder hier warst, muss ich doch doch folgendes loswerden: Dein eventdispatcher ist Spitze!
Habe ihn aus Not beinahe selber erfunden als mir irgendwie schwante, dass es es sowas geben müsste. Design-Patterns? Mal kurz davon gehört aber nicht wirklich verstanden – aber das ist ja genau der Schlüssel...
Tatsächlich musste ich ich einen ähnlichen Dispatcher erfinden, weil deiner ja laut Beschrieb nicht für DOM-Elemnte taugt, die selber target-fähig sind. Mir ging es aber erstmal genau um solche. Inzwischen können die sich super verständigen, indem sie einfach Events abschicken und empfangen, und plötzlich ist alles so einfach wie nie zuvor, ein Quantensprung in der Programmierung!
Hätte nie gedacht, dass ich als Autodidakt mal in solche Sphären vordringen würde, "die nie ein Mensch zuvor gesehen hat..." ;-)
Gruß, Don P
Ein Schelm, wer Schleim dabei denkt...
gruss Don P,
...
Tatsächlich musste ich ich einen ähnlichen Dispatcher erfinden,
weil deiner ja laut Beschrieb nicht für DOM-Elemnte taugt, die
selber target-fähig sind. Mir ging es aber erstmal genau um solche.
...Hätte nie gedacht, dass ich als Autodidakt mal in solche Sphären
vordringen würde, "die nie ein Mensch zuvor gesehen hat..." ; -)
...
Das hatte ich vor mehr als zwei Jahren, was JavaScript betrifft, auch
gedacht. Aber mit jeder in anderen Sprachen bereits etablierten Technik,
die nach JavaScript portiert wird, stehen wir wieder am Anfang einer
neuen Entwicklungsstufe. Und das ist nicht nur fuer »interessierte Laien«
...
Inzwischen können die sich super verständigen, indem sie einfach
Events abschicken und empfangen, und plötzlich ist alles so einfach
wie nie zuvor, ein Quantensprung in der Programmierung!
...
Lass doch mal was von Deinem code sehen. Ich bin ehrlich interessiert.
so long - peterS. - pseliger@gmx.net
Hallo PeterS,
Inzwischen können die sich super verständigen, indem sie einfach
Events abschicken und empfangen, und plötzlich ist alles so einfach
wie nie zuvor, ein Quantensprung in der Programmierung!
...Lass doch mal was von Deinem code sehen. Ich bin ehrlich interessiert.
Hmm, soll ich? Ist vielleicht noch nicht ganz ausgereift... möchte mich ja nicht blamieren, aber was solls. Hier der Code, den ich z.Zt. für eingewisses Projekt benutze:
window.onload = function () {
// common variables:
var tbl={}, r={}, g=window, d=g.document,
el=function(id){return d.getElementById(id);},
hf = (function () { // helper functions
var forOwn = function (o,f) {for(var p in o){if(o.hasOwnProperty(p)){f(p,o[p]);}}},
augment = function (t,o) {forOwn(o,function(p,v){t[p]=v;});return t;},
arrayOf = function (c) {for(var a=[],i=0,e=c[i];e;e=c[++i]){a.push(e);}return a;};
return { forOwn:forOwn, augment:augment, arrayOf:arrayOf, };
})(),
ef = (function(){ // event functions
var queue = [],
fireEvents = function(evtType,data,restore){ // event dispatcher
var restoreElts = 0, targets = evtType && r.ui.events[evtType].targets,
obj = function(evtType,targets,data){return {evtType:evtType,targets:targets,data:data};},
prm = function(obj){evtType=obj.evtType;targets=obj.targets;data=obj.data;};
if(!restore){
data = data || (evtType && r.ui.events[evtType].data);
if (!evtType) { prm(ef.queue[0]); } else if (ef.queue.push(obj(evtType,targets,data))&&ef.queue.length>1){return;};
for (var i=0,elt=targets[i]; elt; elt=targets[++i]){(elt.off=!!elt.disabled)&&(++restoreElts)&&(elt.disabled=false)};
if(restoreElts){g.setTimeout(function(){ef.fireEvents(evtType,data,true);},1);return;} prm(ef.queue.shift());
} else { ef.queue[0] && prm(ef.queue.shift()); }
data && hf.augment(r.ui.events[evtType].dispatch, data);
for(var i=0,elt=targets[i];elt;elt=targets[++i]) { elt.dispatchEvent(r.ui.events[evtType].dispatch)&&(elt.disabled=!!elt.off);}
ef.queue.length && ef.fireEvents();
},
evTarget = function(e){return (e=e||event)&&(e.target||e.srcElement);},
return { queue:queue, fireEvents:fireEvents, evTarget:evTarget, };
})(); // var
r = ({ // root object
ui: ({
elements:{},
handlers: {
btnSimStart: { title: 'Simulation starten',
onclick: function () {this.blur(); /* code... */},
init: function() {/* some code */},
onNoTable: undefined, onPermInput:undefined, onPermInsert: undefined,
},
btnSimStop: { title: 'Simulation stoppen',
onclick: function () {this.blur(); /* code...*/},
onNoTable:undefined, onPermInput:undefined, onPermInsert: undefined,
},
},
events: {
onNoTable: { dispatch:{}, targets: [], run: function(e){ef.evTarget(e).disable(true ,e);} },
onIsTable: { dispatch:{}, targets: [], run: function(e){ef.evTarget(e).disable(false,e);} },
onNewTable: { dispatch:{}, targets: [], run: undefined, data:{/* something */} },
},
common: {
disable: function(bool,e){e&&e.stopPropagation();return (this.disabled=this.off=bool);},
display: function(bool,e){e&&e.stopPropagation();if(this.style)return !(this.style.display=bool?'':'none');},
visible: function(bool,e){e&&e.stopPropagation();if(this.style)return (this.style.visibility=bool?'visible':'hidden');},
},
initIDchildren: function (id, tagName) {
var elt, evtList=this.events, tags=el(id).getElementsByTagName(tagName);
for (var evtType in evtList){ //create & initialize dispatchable events and make them properties of this.events:
evtList[evtType].dispatch=(
function(evtType){var evtObj=d.createEvent("Events");evtObj.initEvent(evtType,true,true);return evtObj;}
)(evtType);
}
for (var i=0,elt=tags[i],id=elt.id; elt; (elt=tags[++i])&&(id=elt.id) ) {
if(!id)continue;
hf.augment(elt, this.common); (id in this.handlers) && hf.augment(elt,this.handlers[id]);
for (var evtType in evtList){
if(evtType in elt){elt.addEventListener(evtType,(elt[evtType]||evtList[evtType].run),false); evtList[evtType].targets.push(elt);}
}
elt.init && elt.init();
this.elements[id]=elt;
}
this.elements.events = evtList; // for fireEvent()
return this.elements;
},
}).initIDchildren('someId','*'), //ui
init: function () {
// possibly more initialization here...
return this;
}
}).init(); //r (root)
//alert('dispatching onNoTable...');
ef.fireEvents('onNoTable'); // Anfangszustand einstellen
};
Viel kürzer ging's nicht, sorry. Habe hoffentlich nicht zu viel rausgenommen.
Es läuft so: onload werden mit initIDchildren('someId','*')
all jene DOM-Elemente mit Funktionalität versehen, die unterhalb des Knotens id="someId" liegen und ein id-Attribut haben.
Jedes erhält die Methoden vom common-Objekt und außerdem alle Methoden und Eigenschaften, die im Objekt handler-Objekt unter ihrer ID notiert sind.
Mögliche Events werden im events-Objekt definiert.
Dort werden sie anfangs automatisch vorbereitet (ihr dispatch-Objekt erzeugt) und unter "run" kann ein Defaulthandler notiert werden, der dann onEvent auszuführen ist.
Im handler-Objekt unter der jeweiligen id kann man auch einen speziellen onBlaBla-handler für jeden Event notieren, der dann Vorrang hat. Falls dort "undefined" steht, gilt der default-handler onBlaBla vom events-Objekt.
Schließlich kann man in events auch ein data-Objekt notieren und/oder mit ef.fireEvents('onBlaBla',{/* dies und das */}) direkt mitgeben. Das Objekt wird dann mit dem Event an alle intressierten Listener weitergereicht.
Da es mir zunächst hauptsächlich darum ging, dass sich Buttons über solche Events aktivieren/deaktivieren lassen, stand ich vor einem großen Problem: Ein input/button oder was immer mit dem Attribut "disabled" reagiert leider auf gar nichts mehr, auch der schönste Event geht ihm sozusagen am A... vorbei.
Der Dispatcher ef.fireEvents ist daher etwas umfangreich geworden: Deaktivierte Elemente werden zunächst aktiviert und der Event erst nach einem kurzen timeout (muss leider sein) gefeuert, dann ggf. wieder deaktiviert (falls nicht gerade der Event zum Aktivieren diente). Damit sich nacheinander gefeuerte Events dabei nicht in die Quere kommen, landen sie ggf. erst in einer Warteschlange.
Fazit: Von hinten durch die Brust ins Auge - aber immerhin Volltreffer ;-)
Das Ganze funktioniert bis jetzt richtig gut. Eigentlich müssten auch noch Vereinfachungen möglich sein, v.a. mit dem events-Objekt bin ich nicht ganz zufrieden. Das sollte wohl eher in ins ef-Objekt verschoben werden...
Gruß, Don P