Saturday, September 12th 2009, 11:29am
Tags
Browser,
crossbrowser,
DOMContentLoaded,
Firefox,
internet explorer,
onload,
onreadystatechange,
ready
Abstract
Wir wollen ein JavaScript ausführen, nachdem die Seite fertig geladen wurde.
Doch das herkömmliche "Seite geladen" ist zu langsam - da dies erst geschieht, wenn auch alle externen Quellen wie Bilder fertig sind.
Um den Event auszuführen nachdem die Hauptseite fertig ist, gibt es für jeden Browser einen eigenen Weg - hier wird eine Plattformunabhängige Lösung vorgestellt.
Article
Dieser Artikel ist noch nicht fertiggestellt
Will man JavaScript Code ausführen, nachdem die Seite fertig geladen wurde benutzt man im Normalfall das onload Event im Body.
|
HTML Code
|
1
|
<body onload="alert('hello world')">
|
Leider führen unterschiedliche Browser diese Funktion zu unterschiedlichen Zeitpunkten aus.
Hat man nun umfangreiche, externe Quellen eingebunden (z.B. Kartenmaterial von Google Maps) dann wird die Funktion erst sehr spät ausgeführt.
Das folgende Beispiel ist so bearbeitet, dass ein Bild für 5 Sekunden lädt. Das eigentliche Script wird also (mit den meisten Browsern) erst nach 5 Sekunden ausgeführt.
http://demo.easy-coding.de/javascript/on…ser/regular.php
Der Firefox kennt das Event "DOMContentLoaded" (
Mozilla Dokumentation), das ausgeführt wird wenn der HTML Code fertig interpretiert wurde. Damit hängt man sich vor nachgelagerte Scripte oder eingebundene Bilder.
|
JavaScript Code
|
1
2
3
|
document.addEventListener("DOMContentLoaded", function(){
alert('firefox sagt: fertig');
}, false);
|
Wofür der Firefox Lösungen bietet, hat der Internet Explorer leider nur Workarounds.
Diese reichen über das mittels "defer" verzögerte Einhängen von externen <script> Elementen bis hin zu einem "Linksscrollen" das erst funktioniert, wenn die Seite fertig geladen wurde. Da das einhängen externer Scripte mehr Ressourcen verbraucht hat sich das JavaScript Framework jquery (in Version 1.3.2) für letzten Workaround entschieden.
Daher wird er auch hier behandelt.
|
JavaScript Code
|
1
2
3
4
5
6
7
8
9
10
11
|
(function () {
try {
// throws errors until after ondocumentready
d.documentElement.doScroll('left');
} catch (e) {
setTimeout(arguments.callee, 50);
return;
}
// no errors, fire
alert('internet explorer sagt: fertig');
})();
|
Microsoft dokumentiert diesen Weg für alle bisher verfügbaren IE Versionen:
http://msdn2.microsoft.com/en-us/library/ms531426.aspx.
Durch die Closure um den eigentlichen Event und die Verwendung von arguments.callee, das die Closure referenziert sind wir übrigens in einer Endlosschleife, dir wir im 50 Millisekunden Takt aufrufen.
Wenn das Leben nicht schon schwierig genug wäre, so bieten die verschiedenen Browser noch unterschiedliche Methoden um Events hinzuzufügen.
Diese Problematik wird im Script behandelt, auch wenn in diesem Wiki Artikel nicht darauf eingegangen wird.
Die Anforderung an unser Script ist nun einerseits, dass man beliebig viele Events hinzufügen kann - andererseits sollen die Events auch noch gefeuert werden, wenn der Event versucht wird hinzuzufügen nachdem die Seite schon fertig ist.
Dafür gibt es eine Abfrage beim hinzufügen der Events:
|
JavaScript Code
|
1
2
3
4
5
6
7
8
9
|
// If the DOM is already ready
if ( this.isReady )
// Execute the function immediately
fn.call( window, this );
// Otherwise, remember the function for later
else
// Add the function to the wait list
this.readyList.push( fn );
|
Das Script ist als ready.js unter MIT/GPL Lizenzierung frei zur Verfügung. Für die produktive Verwendung empfiehlt sich die Verwendung der minimierten Version:
ready.min.js (0,4 KB gzipped)
Für Tests könnt ihr außerdem den vollen Quelltext herunterladen: ready.js (3,2 KB)
Nach Einbindung fügt man Funktionen über folgende Syntax hinzu:
|
HTML Code
|
1
2
3
4
5
6
|
<script type="text/javascript" src="ready.min.js"></script>
<script type="text/javascript">
ready.push(function() {
alert('ready event geladen');
});
</script>
|
Eine Live Demo findet ihr unter
http://demo.easy-coding.de/javascript/on…-cross-browser/.
|
JavaScript Code
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
|
/**
* ready.js
*
* Author: Torben Brodt <[email]t.brodt@gmail.com[/email]>
* Summary: Cross-browser wrapper for DOMContentLoaded
* Updated: 07/09/2009
* License: MIT / GPL
* Version: 1.1
*
* URL:
* [url]http://www.easy-coding.de[/url]
* [url]http://jquery.com/dev/svn/trunk/jquery/MIT-LICENSE.txt[/url]
* [url]http://jquery.com/dev/svn/trunk/jquery/GPL-LICENSE.txt[/url]
*
* Full Description:
* A page has loaded after all external resources like images have been loaded.
* Should all scripts wait for that? a better bevaviour is to wait for the dom content being ready.
*
* This script has workarounds for all the big browsers meaning the major versions of firefox, internet explorer, opera, safari and chrome.
* You can use it without risk, since the normal "onload" behavior is the fallback solution.
*
* Most of the source is lended from jquery
*/
var ready = new (function () {
var readyBound = 0, d = document, w = window, t = this, x;
t.isReady = 0;
t.readyList = [];
function bindReady() {
if ( readyBound ) return;
readyBound = 1;
// Mozilla, Opera and webkit nightlies currently support this event
if ( d.addEventListener ) {
// Use the handy event callback
x = "DOMContentLoaded";
d.addEventListener( x, function(){
d.removeEventListener( x, arguments.callee, false );
ready.ready();
}, false );
// If IE event model is used
} else if ( d.attachEvent ) {
// ensure firing before onload,
// maybe late but safe also for iframes
x = "onreadystatechange";
d.attachEvent(x, function(){
if ( d.readyState === "complete" ) {
d.detachEvent( x, arguments.callee );
ready.ready();
}
});
// If IE and not an iframe
// continually check to see if the document is ready
if ( d.documentElement.doScroll && w == w.top ) (function(){
if ( t.isReady ) return;
try {
// If IE is used, use the trick by Diego Perini
// [url]http://javascript.nwbox.com/IEContentLoaded/[/url]
d.documentElement.doScroll("left");
} catch( error ) {
setTimeout( arguments.callee, 0 );
return;
}
// and execute any waiting functions
ready.ready();
})();
}
// A fallback to window.onload, that will always work
w.onload = ready.ready; // TODO: compliant? t.event.add( window, "load", t.ready );
};
// Handle when the DOM is ready
t.ready = function() {
// Make sure that the DOM is not already loaded
if ( !t.isReady ) {
// Remember that the DOM is ready
t.isReady = 1;
// If there are functions bound, to execute
if ( t.readyList ) {
// Execute all of them
for(var i=0; i<t.readyList.length; i++) {
t.readyList[i].call( w, t );
};
// Reset the list of functions
t.readyList = null;
}
// Trigger any bound ready events
d.loaded = true; // TODO: compliant? this(document).triggerHandler("ready");
}
};
// adds funtion to readyList if not ready yet, otherwise call immediately
t.push = function(fn) {
// Attach the listeners
bindReady();
// If the DOM is already ready
if ( t.isReady )
// Execute the function immediately
fn.call( w, t );
// Otherwise, remember the function for later
else
// Add the function to the wait list
t.readyList.push( fn );
return t;
};
})();
|
Request deletion
report critical content