深入理解js中的加載事件
前面的話
提到加載事件,可能想到了window.onload,但實(shí)際上,加載事件是一大類事件,本文將詳細(xì)介紹加載事件
load
load事件是最常用的一個(gè)事件,當(dāng)頁(yè)面完全加載后(包括所有圖像、javascript文件、CSS文件等外部資源),就會(huì)觸發(fā)window上的load事件
[注意]IE8-瀏覽器不會(huì)為該事件設(shè)置srcElement屬性,而其他瀏覽器的target屬性指向document
window.onload = function(e){
e = e || event;
var target = e.target || e.srcElement;
//IE8-瀏覽器返回null,其他瀏覽器返回document
console.log(target);
}
load事件不僅發(fā)生在document對(duì)象,還發(fā)生在各種外部資源上面。瀏覽網(wǎng)頁(yè)就是一個(gè)加載各種資源的過(guò)程,圖像(image)、樣式表(style sheet)、腳本(script)、視頻(video)、音頻(audio)、Ajax請(qǐng)求(XMLHttpRequest)等等。這些資源和document對(duì)象、window對(duì)象、XMLHttpRequestUpload對(duì)象,都會(huì)觸發(fā)load事件
[注意]如果頁(yè)面從瀏覽器緩存加載,并不會(huì)觸發(fā)load事件
圖像和框架iframe也可以觸發(fā)load事件
[注意]要在指定圖像的src屬性之前先指定事件,圖像是從設(shè)置src屬性之后開(kāi)始下載
var img = new Image();
img.onload = function(){
document.body.appendChild(img);
}
img.src="http://sandbox.runjs.cn/uploads/rs/26/ddzmgynp/chunfen.jpg";
<iframe id="test" src="http://cnblogs.com" frameborder="0"></iframe>
<script>
test.onload = function(){
console.log(666);
}
</script>
script元素也可以觸發(fā)load事件,以便開(kāi)發(fā)人員確定動(dòng)態(tài)加載的javascript文件是否加載完畢。與圖像不同,只有在設(shè)置了script元素的src屬性并將該元素添加到文檔后,才會(huì)開(kāi)始下載javascript文件。換句話說(shuō),指定src屬性和指定事件處理程序的先后順序不重要
[注意]IE8-瀏覽器不支持該用法
var script = document.createElement('script');
script.onload = function(){
console.log(666);
}
document.body.appendChild(script);
script.src=http://files.cnblogs.com/files/xiaohuochai/excanvas.js;
類似地,link元素可以觸發(fā)load事件,且無(wú)兼容性問(wèn)題。與script類似,在未指定href屬性并將link元素添加到文檔之前也不會(huì)開(kāi)始下載樣式表
類似地,link元素可以觸發(fā)load事件,且無(wú)兼容性問(wèn)題。與script類似,在未指定href屬性并將link元素添加到文檔之前也不會(huì)開(kāi)始下載樣式表
error
load事件在加載成功時(shí)觸發(fā),而error事件與之正相反,在加載失敗時(shí)觸發(fā)。凡是可以觸發(fā)load事件的元素,同樣可以觸發(fā)error事件
任何沒(méi)有通過(guò)try-catch處理的錯(cuò)誤都會(huì)觸發(fā)window對(duì)象的error事件
error事件可以接收三個(gè)參數(shù):錯(cuò)誤消息、錯(cuò)誤所在的URL和行號(hào)。多數(shù)情況下,只有錯(cuò)誤消息有用,因?yàn)閁RL只是給出了文檔的位置,而行號(hào)所指的代碼行既可能出自嵌入的javascript代碼,也可能出自外部的文件
要指定onerror事件處理程序,可以使用DOM0級(jí)技術(shù),也可以使用DOM2級(jí)事件的標(biāo)準(zhǔn)格式
//DOM0級(jí)
window.onerror = function(message,url,line){
alert(message);
}
//DOM2級(jí)
window.addEventListener("error",function(message,url,line){
alert(message);
});
瀏覽器是否顯示標(biāo)準(zhǔn)的錯(cuò)誤消息,取決于onerror的返回值。如果返回值為false,則在控制臺(tái)中顯示錯(cuò)誤消息;如果返回值為true,則不顯示
//控制臺(tái)顯示錯(cuò)誤消息
window.onerror = function(message,url,line){
alert(message);
return false;
}
a;
//控制臺(tái)不顯示錯(cuò)誤消息
window.onerror = function(message,url,line){
alert(message);
return true;
}
a;
這個(gè)事件處理程序是避免瀏覽器報(bào)告錯(cuò)誤的最后一道防線。理想情況下,只要可能就不應(yīng)該使用它。只要能夠適當(dāng)?shù)厥褂胻ry-catch語(yǔ)句,就不會(huì)有錯(cuò)誤交給瀏覽器,也就不會(huì)觸發(fā)error事件
圖像也支持error事件。只要圖像的src特性中的URL不能返回可以被識(shí)別的圖像格式,就會(huì)觸發(fā)error事件。此時(shí)的error事件遵循DOM格式,會(huì)返回一個(gè)以圖像為目標(biāo)的event對(duì)象
發(fā)生error事件時(shí),圖像下載過(guò)程已經(jīng)結(jié)束,也就是不能再重新下載了。但是,可以在error事件中,重新設(shè)置圖像的src屬性,指向備用圖像的地址
var image = new Image();
document.body.appendChild(image);
image.onerror = function(e){
image.src = 'smileBackup.gif';
}
image.src = 'smilex.gif';
abort
元素加載中止時(shí),(如加載過(guò)程中按下ESC鍵,停止加載),觸發(fā)該事件,常用于圖片加載
[注意]只有IE瀏覽器支持
var image = new Image();
image.onabort = function(){
console.log(111);
}
document.body.appendChild(image);
image.src = 'http://sandbox.runjs.cn/uploads/rs/26/ddzmgynp/chunfen.jpg';
unload
與load事件對(duì)應(yīng)的是unload事件,該事件在文檔被完全卸載后觸發(fā)。一般地,在刷新頁(yè)面時(shí),會(huì)觸發(fā)該事件
chrome/firefox/safari瀏覽器會(huì)阻止alert等對(duì)話框,IE瀏覽器會(huì)阻止console.log()等控制臺(tái)顯示
window.onunload = function(e){
//chrome報(bào)錯(cuò),firefox靜默失敗,IE彈出666
alert(666);
}
window.onunload = function(e){
//chrome和firefox控制臺(tái)顯示666,IE靜默失敗
console.log(666);
}
beforeunload
beforeunload事件在關(guān)閉網(wǎng)頁(yè)或刷新網(wǎng)頁(yè)時(shí)觸發(fā)。它一般地用來(lái)防止用戶不小心關(guān)閉網(wǎng)頁(yè)
如果要讓beforeunload事件生效,必須滿足以下兩個(gè)條件之一:1、事件處理程序返回一個(gè)真值;2、事件對(duì)象event.returnValue返回一個(gè)真值。如果兩個(gè)條件同時(shí)滿足,則以第一個(gè)條件為準(zhǔn)
chrome/safari/firefox在對(duì)話框中不顯示指定文本,只顯示默認(rèn)文本。而IE瀏覽器會(huì)在對(duì)話框中顯示返回值或returnValue值
window.onbeforeunload = function(e){
e = e || event;
//IE瀏覽器顯示指定文本,其他瀏覽器顯示默認(rèn)文本
e.returnValue = '要離開(kāi)嗎?';
}
DOMContentLoaded
window的onload事件會(huì)在頁(yè)面中的一切都加載完畢時(shí)觸發(fā),但這個(gè)過(guò)程可能會(huì)因?yàn)橐虞d的外部資源過(guò)多而頗費(fèi)周折。而DOMContentLoaded事件則在形成完整的DOM樹之后就會(huì)觸發(fā),而不理會(huì)圖像、javascript文件、CSS文件或其他資源是否下載完畢。與load事件不同,DOMContentLoaded支持在頁(yè)面下載的早期添加事件處理程序,這也就意味著用戶能夠盡早地與頁(yè)面進(jìn)行交互
[注意]網(wǎng)頁(yè)的javascript腳本是同步執(zhí)行的,所以定義DOMContentLoaded事件的監(jiān)聽(tīng)函數(shù),應(yīng)該放在所有腳本的最前面。否則腳本一旦發(fā)生堵塞,將推遲觸發(fā)DOMContentLoaded事件
要處理DOMContentLoaded事件,可以為document或window添加相應(yīng)的事件處理程序,盡管這個(gè)事件會(huì)冒泡到window,但它的目標(biāo)實(shí)際上是document
[注意]IE8-瀏覽器不支持該事件
window.addEventListener('DOMContentLoaded',function(e){
console.log(1);
})
對(duì)于不支持該事件的瀏覽器如IE8-瀏覽器,可以在頁(yè)面加載期間設(shè)置一個(gè)時(shí)間為0毫秒的超時(shí)調(diào)用,且必須作為頁(yè)面的第一個(gè)超時(shí)調(diào)用
setTimeout(function(){
console.log(1);
},0)
readystatechange
readystatechange事件發(fā)生在Document對(duì)象和XMLHttpRequest對(duì)象,它們的readyState屬性發(fā)生變化時(shí)觸發(fā)
這個(gè)事件的目的是提供與文檔或元素的加載狀態(tài)有關(guān)的信息。支持readystatechange事件的每個(gè)對(duì)象都有一個(gè)readyState屬性,可能包含下列5個(gè)值中的一個(gè)
uninitialized(未初始化):對(duì)象存在但尚未初始化 loading(正在加載):對(duì)象正在加載數(shù)據(jù) loaded(加載完畢):對(duì)象加載數(shù)據(jù)完成 interactive(交互):可以操作對(duì)象了,但還沒(méi)有完全加載 complete(完成):對(duì)象已經(jīng)加載完畢
這些狀態(tài)看起來(lái)很直觀,但并非所有對(duì)象都會(huì)經(jīng)歷readyState的這幾個(gè)階段。換句話說(shuō),如果某個(gè)階段不適用某個(gè)對(duì)象,則該對(duì)象完全可能跳過(guò)該階段;并沒(méi)有規(guī)定哪個(gè)階段適用于哪個(gè)對(duì)象。顯然,這意味著readystatechange事件經(jīng)常會(huì)少于4次,而readyState屬性的值也不總是連續(xù)的
對(duì)于document而言,值為"interactive"的readyState會(huì)在與DOMContentLoaded大致相同的時(shí)刻觸發(fā)readystatechange事件。此時(shí),DOM樹已經(jīng)加載完畢,可以安全地操作它了,因此就會(huì)進(jìn)入交互(interactive)階段。但與此同時(shí),圖像及其他外部文件不一定可用
//'interactive' 'complete'
document.onreadystatechange = function(e){
if(document.readyState == 'uninitialized'){
console.log('uninitialized');
}
if(document.readyState == 'loading'){
console.log('loading');
}
if(document.readyState == 'loaded'){
console.log('loaded');
}
if(document.readyState == 'interactive'){
console.log('interactive');
}
if(document.readyState == 'complete'){
console.log('complete');
}
}
在與load事件一起使用時(shí),無(wú)法預(yù)測(cè)兩個(gè)事件觸發(fā)的先后順序。在包含較多或較大的外部資源的頁(yè)面中,會(huì)在load事件觸發(fā)之前先進(jìn)入交互階段;而在包含較少或較小的外部資源的頁(yè)面中,則很難說(shuō)readystatechange事件會(huì)發(fā)生在load事件前面
讓問(wèn)題變得更復(fù)雜的是,交互階段可能會(huì)早于也可能會(huì)晚于完成階段出現(xiàn),無(wú)法確保順序。在包含較多外部資源的頁(yè)面中,交互階段更有可能早于完成階段出現(xiàn);而在頁(yè)面中包含較少外部資源的情況下,完成階段先于交互階段出現(xiàn)的可能性更大。因此,為了盡可能搶到先機(jī),有必要同時(shí)檢測(cè)交互和完成階段
document.onreadystatechange = function(){
if(document.readyState == 'interactive' || document.readyState == 'complete'){
console.log('loaded');
document.onreadystatechange = null;
}
}
對(duì)于上面的代碼來(lái)說(shuō),當(dāng)readystatechange事件觸發(fā)時(shí),會(huì)檢測(cè)document.readyState的值,看當(dāng)前是否已經(jīng)進(jìn)入交互階段或完成階段。如果是,則移除相應(yīng)的事件處理程序以免在其他階段再執(zhí)行
另外,IE10-瀏覽器支持給script元素和link元素觸發(fā)readystatechange事件,用來(lái)確定外部的javascript或css文件是否已經(jīng)加載完成
var script = document.createElement('script');
script.onreadystatechange = function(){
if( script.readyState == 'loaded' || script.readyState == 'complete'){
console.log('loaded');
script.onreadystatechange = null;
}
}
script.src="js/digit.js";
document.body.appendChild(script);
var link = document.createElement('link');
link.rel="stylesheet";
link.onreadystatechange = function(){
if( link.readyState == 'loaded' || link.readyState == 'complete'){
console.log('loaded');
link.onreadystatechange = null;
}
}
link.href="test.css" rel="external nofollow" ;
document.getElementsByTagName('body')[0].appendChild(link);
以上就是本文的全部?jī)?nèi)容,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作能帶來(lái)一定的幫助,同時(shí)也希望多多支持腳本之家!
相關(guān)文章
JavaScript設(shè)計(jì)模式之觀察者模式(發(fā)布訂閱模式)原理與實(shí)現(xiàn)方法示例
這篇文章主要介紹了JavaScript設(shè)計(jì)模式之觀察者模式(發(fā)布訂閱模式)原理與實(shí)現(xiàn)方法,結(jié)合實(shí)例形式分析了JavaScript觀察者模式概念、原理、使用方法及相關(guān)操作注意事項(xiàng),需要的朋友可以參考下2018-07-07
使用clipboard.js庫(kù)實(shí)現(xiàn)復(fù)制剪切功能
這篇文章介紹了clipboard.js實(shí)現(xiàn)復(fù)制功能的方法,文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-06-06
一個(gè)檢測(cè)表單數(shù)據(jù)的JavaScript實(shí)例
這篇文章主要介紹了一個(gè)檢測(cè)表單數(shù)據(jù)的JavaScript實(shí)例,很簡(jiǎn)單,很實(shí)用,比較適合初學(xué)者2014-10-10
js 獲取范圍內(nèi)的隨機(jī)數(shù)實(shí)例代碼
下面小編就為大家?guī)?lái)一篇js 獲取范圍內(nèi)的隨機(jī)數(shù)實(shí)例代碼。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2016-08-08
js 獲取元素的具體樣式信息getcss(實(shí)例講解)
下面小編就為大家?guī)?lái)一篇js 獲取元素的具體樣式信息getcss(實(shí)例講解)。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-07-07
ion content 滾動(dòng)到底部會(huì)遮住一部分視圖的快速解決方法
本文給大家?guī)?lái)了ion content 滾動(dòng)到底部會(huì)遮住一部分視圖的快速解決方法,其實(shí)解決方法超簡(jiǎn)單的,只要在你的controller里面預(yù)先注入$ionicScrollDelegate就可以了,感興趣的朋友通過(guò)本文一起學(xué)習(xí)吧2016-09-09
詳解JavaScript中的鏈?zhǔn)秸{(diào)用
這篇文章主要介紹了JavaScript中的鏈?zhǔn)秸{(diào)用的相關(guān)資料,幫助大家更好的理解和學(xué)習(xí)JavaScript,感興趣的朋友可以了解下2020-11-11

