Ok, to może być tylko głupie pytanie, choć jestem pewien, że jest mnóstwo innych ludzi, którzy zadają to samo pytanie od czasu do czasu. Ja, po prostu chcę się upewnić w 100%, że tak czy inaczej jest to możliwe. Z jQuery wszyscy znamy wspaniałą
$('document').ready(function(){});
Jednak powiedzmy, że chcę uruchomić funkcję, która jest napisana w standardowym JavaScripcie bez żadnej biblioteki wspierającej ją, i że chcę uruchomić funkcję, gdy tylko strona jest gotowa do jej obsługi. Jaki jest właściwy sposób podejścia do tego?
Wiem, że mogę zrobić:
window.onload="myFunction()";
...lub mogę użyć tagu body
:
<body onload="myFunction()">
...lub mogę nawet spróbować na dole strony po wszystkim, ale koniec body
lub html
tag jak:
<script type="text/javascript">
myFunction();
</script>
Jaka jest zgodna z przeglądarkami (stara/nowa) metoda wydawania jednej lub więcej funkcji w sposób podobny do jQuery's $.ready()
?
Najprostszą rzeczą do zrobienia w przypadku braku frameworka, który robi wszystko dla kompatybilności między przeglądarkami, jest po prostu umieszczenie wywołania do swojego kodu na końcu ciała. Jest to szybsze do wykonania niż obsługa onload
, ponieważ czeka tylko na DOM, aby być gotowym, a nie na wszystkie obrazy do załadowania. I, to działa w każdej przeglądarce.
<!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>
Dla nowoczesnych przeglądarek (wszystko od IE9 i nowszych oraz dowolna wersja Chrome, Firefox lub Safari), jeśli chcesz być w stanie zaimplementować metodę jQuery jak $(document).ready()
, którą możesz wywołać z dowolnego miejsca (bez martwienia się o to, gdzie skrypt wywołujący jest umieszczony), możesz po prostu użyć czegoś takiego:
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);
}
}
Użycie:
docReady(function() {
// DOM is loaded and ready for manipulation here
});
Jeśli potrzebujesz pełnej kompatybilności z różnymi przeglądarkami (włączając w to stare wersje IE) i nie chcesz czekać na window.onload
, to prawdopodobnie powinieneś przyjrzeć się temu, jak framework taki jak jQuery implementuje swoją metodę $(document).ready()
. Jest to dość skomplikowane w zależności od możliwości przeglądarki.
Aby dać ci mały pomysł, co robi jQuery (który będzie działał wszędzie tam, gdzie umieszczony jest znacznik script).
Jeśli jest obsługiwany, próbuje standardu:
document.addEventListener('DOMContentLoaded', fn, false);
z opcją awaryjną do:
window.addEventListener('load', fn, false )
lub dla starszych wersji IE, używa:
document.attachEvent("onreadystatechange", fn);
z opcją awaryjną do:
window.attachEvent("onload", fn);
I, istnieją pewne obejścia w ścieżce kodu IE, które nie'całkiem podążają, ale wygląda na to, że ma to coś wspólnego z ramkami.
Tutaj jest pełny zamiennik dla jQuery's .ready()
napisany w zwykłym 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);
Najnowsza wersja kodu jest udostępniona publicznie na GitHubie pod adresem https://github.com/jfriend00/docReady.
Użycie:
// 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);
Zostało to przetestowane w:
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
Robocza implementacja i stanowisko testowe:
Oto podsumowanie tego, jak to działa:
docReady(fn, context)
.docReady(fn, context)
jest wywoływany, sprawdź czy ready handler już wystrzelił. Jeśli tak, po prostu zaplanuj nowo dodany callback tak, aby odpalił się zaraz po tym, jak ten wątek JS zakończy się za pomocą setTimeout(fn, 1)
.document.addEventListener
istnieje, zainstaluj obsługę zdarzeń używając .addEventListener()
dla obu zdarzeń "DOMContentLoaded"
i "load"
. Zdarzenie "load" jest zdarzeniem zapasowym dla bezpieczeństwa i nie powinno być potrzebne.document.addEventListener
nie istnieje, to zainstaluj obsługę zdarzeń używając .attachEvent()
dla zdarzeń "onreadystatechange"
i "onload"
.onreadystatechange
sprawdź, czy document.readyState == "complete"
i jeśli tak, wywołaj funkcję odpalającą wszystkie ready handlery.Handlerzy zarejestrowani za pomocą docReady()
mają gwarancję, że będą uruchamiane w kolejności w jakiej zostały zarejestrowane.
Jeśli wywołasz docReady(fn)
po tym jak dokument jest już gotowy, wywołanie zwrotne zostanie zaplanowane do wykonania jak tylko bieżący wątek wykonania zakończy się używając setTimeout(fn, 1)
. Pozwala to kodowi wywołującemu zawsze zakładać, że są to wywołania asynchroniczne, które zostaną wywołane później, nawet jeśli później jest tak szybko, jak tylko zakończy się bieżący wątek JS i zachowuje kolejność wywoływania.
Twoja metoda (umieszczenie skryptu przed zamykającym znacznikiem body)
<script>
myFunction()
</script>
</body>
</html>
jest niezawodnym sposobem na obsługę starych i nowych przeglądarek.