Okay, det er måske bare et dumt spørgsmål, selv om jeg er sikker på, at der er masser af andre, der stiller det samme spørgsmål fra tid til anden. Mig, jeg vil bare gerne være 100% sikker på det uanset hvad. Med jQuery kender vi alle den vidunderlige
$('document').ready(function(){});
Men lad os sige, at jeg ønsker at køre en funktion, der er skrevet i standard JavaScript uden noget bibliotek bagved, og at jeg ønsker at starte en funktion, så snart siden er klar til at håndtere den. Hvad'er den korrekte måde at gribe dette an på?
Jeg ved, at jeg kan gøre det:
window.onload="myFunction()";
...eller jeg kan bruge body
-tag:
<body onload="myFunction()">
...eller jeg kan endda prøve nederst på siden efter alt, men i slutningen af body
eller html
tagget som f.eks:
<script type="text/javascript">
myFunction();
</script>
Hvad er en cross-browser(gammel/ny)-kompatibel metode til at udstede en eller flere funktioner på en måde som jQuery's $.ready()
?
Det enkleste at gøre, hvis du ikke har en ramme, der klarer kompatibiliteten på tværs af browsere for dig, er blot at indsætte et kald til din kode i slutningen af kroppen. Dette er hurtigere at udføre end en onload
-handler, fordi denne kun venter på at DOM'en er klar, ikke på at alle billeder indlæses. Og det virker i alle browsere.
<!doctype html>
<html>
<head>
</head>
<body>
Your HTML here
<script>
// self executing function here
(function() {
// your page initialization code here
// the DOM will be available here
})();
</script>
</body>
</html>
For moderne browsere (alt fra IE9 og nyere og enhver version af Chrome, Firefox eller Safari), hvis du ønsker at kunne implementere en jQuery-lignende $(document).ready()
-metode, som du kan kalde fra hvor som helst (uden at bekymre dig om, hvor det kaldende script er placeret), kan du bare bruge noget som dette:
function docReady(fn) {
// see if DOM is already available
if (document.readyState === "complete" || document.readyState === "interactive") {
// call on next available tick
setTimeout(fn, 1);
} else {
document.addEventListener("DOMContentLoaded", fn);
}
}
Anvendelse:
docReady(function() {
// DOM is loaded and ready for manipulation here
});
Hvis du har brug for fuld kompatibilitet på tværs af browsere (herunder gamle versioner af IE), og du ikke ønsker at vente på window.onload
, så bør du nok kigge på, hvordan et framework som jQuery implementerer sin $(document).ready()
-metode. Det'er ret indviklet afhængig af browserens muligheder.
For at give dig en lille idé om hvad jQuery gør (som vil virke uanset hvor script tagget er placeret).
Hvis den understøttes, prøver den standarden:
document.addEventListener('DOMContentLoaded', fn, false);
med en fallback til:
window.addEventListener('load', fn, false )
eller for ældre versioner af IE, bruger den:
document.attachEvent("onreadystatechange", fn);
med en fallback til:
window.attachEvent("onload", fn);
Og, der er nogle work-arounds i IE kode stien, som jeg ikke helt følger, men det ser ud til at det har noget at gøre med frames.
Her er en komplet erstatning for jQuery's .ready()
skrevet i almindeligt javascript:
(function(funcName, baseObj) {
// The public function name defaults to window.docReady
// but you can pass in your own object and own function name and those will be used
// if you want to put them in a different namespace
funcName = funcName || "docReady";
baseObj = baseObj || window;
var readyList = [];
var readyFired = false;
var readyEventHandlersInstalled = false;
// call this when the document is ready
// this function protects itself against being called more than once
function ready() {
if (!readyFired) {
// this must be set to true before we start calling callbacks
readyFired = true;
for (var i = 0; i < readyList.length; i++) {
// if a callback here happens to add new ready handlers,
// the docReady() function will see that it already fired
// and will schedule the callback to run right after
// this event loop finishes so all handlers will still execute
// in order and no new ones will be added to the readyList
// while we are processing the list
readyList[i].fn.call(window, readyList[i].ctx);
}
// allow any closures held by these functions to free
readyList = [];
}
}
function readyStateChange() {
if ( document.readyState === "complete" ) {
ready();
}
}
// This is the one public interface
// docReady(fn, context);
// the context argument is optional - if present, it will be passed
// as an argument to the callback
baseObj[funcName] = function(callback, context) {
if (typeof callback !== "function") {
throw new TypeError("callback for docReady(fn) must be a function");
}
// if ready has already fired, then just schedule the callback
// to fire asynchronously, but right away
if (readyFired) {
setTimeout(function() {callback(context);}, 1);
return;
} else {
// add the function and context to the list
readyList.push({fn: callback, ctx: context});
}
// if document already ready to go, schedule the ready function to run
if (document.readyState === "complete") {
setTimeout(ready, 1);
} else if (!readyEventHandlersInstalled) {
// otherwise if we don't have event handlers installed, install them
if (document.addEventListener) {
// first choice is DOMContentLoaded event
document.addEventListener("DOMContentLoaded", ready, false);
// backup is window load event
window.addEventListener("load", ready, false);
} else {
// must be IE
document.attachEvent("onreadystatechange", readyStateChange);
window.attachEvent("onload", ready);
}
readyEventHandlersInstalled = true;
}
}
})("docReady", window);
Den seneste version af koden er delt offentligt på GitHub på https://github.com/jfriend00/docReady
Anvendelse:
// pass a function reference
docReady(fn);
// use an anonymous function
docReady(function() {
// code here
});
// pass a function reference and a context
// the context will be passed to the function as the first argument
docReady(fn, context);
// use an anonymous function with a context
docReady(function(context) {
// code here that can use the context argument that was passed to docReady
}, ctx);
Dette er blevet testet i:
IE6 and up
Firefox 3.6 and up
Chrome 14 and up
Safari 5.1 and up
Opera 11.6 and up
Multiple iOS devices
Multiple Android devices
Arbejdende implementering og testbed:
Her er et resumé af, hvordan det fungerer:
docReady(fn, context)
docReady(fn, context)
kaldes, kontrolleres det, om ready-handleren allerede er blevet udløst. Hvis det er tilfældet, skal du blot planlægge den nyligt tilføjede callback til at blive udløst lige efter, at denne JS-tråd er afsluttet med setTimeout(fn, 1)
.document.addEventListener
findes, installer da event handlers ved hjælp af .addEventListener()
for både &"DOMContentLoaded"
og "load"
events. "load" er en backup-hændelse af sikkerhedshensyn og bør ikke være nødvendig.document.addEventListener
ikke eksisterer, skal du installere event handlers ved hjælp af .attachEvent()
for &"onreadystatechange"
og "onload"
events.onreadystatechange
kontrolleres det, om document.readyState === "complete"
, og hvis det er tilfældet, kaldes en funktion, der affyrer alle ready-handlerne.Handlers registreret med docReady()
er garanteret at blive affyret i den rækkefølge, de blev registreret.
Hvis du kalder docReady(fn)
efter at dokumentet allerede er klar, vil callbacken blive planlagt til at blive udført, så snart den aktuelle udførelsestråd er færdig med setTimeout(fn, 1)
. Dette gør det muligt for den kaldende kode altid at antage, at der er tale om asynkrone callbacks, som vil blive kaldt senere, selv om senere er så snart den aktuelle JS-tråd er færdig, og det bevarer kaldsrækkefølgen.
Din metode (placering af scriptet før det afsluttende body tag)
<script>
myFunction()
</script>
</body>
</html>
er en pålidelig måde at understøtte gamle og nye browsere på.