<img>標籤是頁面上最爲重要的元素之一。很難想象一個頁面上沒有圖片的樣子,這樣的頁面效果將會大打折扣。javascript
任何一個前端工程師想必對<img>標籤都很是熟悉了,畢竟常常和它打交道嘛。但你真的對它徹底瞭解嗎?若是你能準確無誤地回答出如下幾個關於<img>的問題,那麼恭喜你,本文你能夠再也不往下看了,或者說你能夠用省視的目光來覈對本文。html
-
問題1:若是在一個頁面上插入<img>標籤,有哪些屬性是必需的?前端
-
問題2:<img>標籤在HTML和XHTML中有什麼區別?java
-
問題3:在一個頁面上插入<img>標籤,爲何說最好要使用height和width屬性?chrome
-
問題4:<img>標籤的onload/onerror/onabort事件,在什麼狀況下會被觸發?編程
-
問題5:咱們通常知道,當一個圖片請求返回404時,會觸發onerror事件,那當圖片請求返回302時,會觸發onerror事件嗎?304呢?403呢?500呢?請求超時呢?甚至說當返回200,但內容並不是是圖片時,也會觸發onerror麼?跨域
-
問題6:圖片觸發onerror事件時,能使用javascript獲取到圖片請求的響應代碼麼?瀏覽器
-
問題7:咱們通常知道,<img>標籤能夠用來發起跨域請求,你能手寫出一段正確使用<img>發起跨域請求的javascript代碼麼?緩存
-
問題8:用戶是能夠設置瀏覽器不顯示圖片的,尤爲是在移動設備上,用戶爲了節省流量,每每會進行那麼,如何獲知用戶是否禁止瀏覽圖片呢?前端工程師
問題已經提出,你能回答出哪幾個呢?事實上,在沒有查看標準和親自作試驗以前,筆者對其中一些問題的答案也是模棱兩可,不敢確保本身的答案100%準確。
下面,咱們逐一分析和解答上述的8個問題:
問題1:若是在一個頁面上插入<img>標籤,有哪些屬性是必需的?
答案是src和alt。
實例:(本實例摘自W3school: http://www.w3school.com.cn )
<img src=" http://www.w3school.com.cn/i/eg_tulip.jpg" alt="上海鮮花港 - 鬱金香" />
src屬性規定了顯示圖像的URL,瀏覽器會對該URL發起Http Get請求。
alt屬性則規定了圖像的替代文本,在圖像沒法顯示或者用戶禁用圖像顯示時,代替圖像顯示在瀏覽器中的內容。以下圖:
與src屬性相比較,alt屬性更容易被設計人員和開發人員所忽視,事實上,在筆者撰寫本文時,即便在國內一些大型門戶網站首頁上(例如新浪、搜狐),咱們也能夠找到許多沒有alt屬性的<img>標籤。但筆者強烈推薦在文檔的每一個圖像中都使用這個屬性,這樣即便圖像沒法顯示,用戶仍是能夠看到的一些相關信息,從而大大提升了頁面的用戶友好性。
問題2:<img>標籤在HTML和XHTML中有什麼區別?
(答案摘自W3school: http://www.w3school.com.cn)
在 HTML 中,<img> 標籤沒有結束標籤。例如:
<img src=" http://www.w3school.com.cn/i/eg_tulip.jpg" alt="上海鮮花港 - 鬱金香" >
在 XHTML 中,<img> 標籤必須被正確地關閉。
<img src=" http://www.w3school.com.cn/i/eg_tulip.jpg" alt="上海鮮花港 - 鬱金香" />
在 HTML 4.01 中,不推薦使用 image 元素的 "align"、"border"、"hspace" 以及 "vspace" 屬性。在 XHTML 1.0 Strict DTD 中,不支持 image 元素的 "align"、"border"、"hspace" 以及 "vspace" 屬性。
問題3:在一個頁面上插入<img>標籤,爲何說最好要使用height和width屬性?
您在瀏覽網頁的時候,可能會遇到這種狀況:隨着頁面中的圖像加載併成功顯示,頁面上的內容會隨之發生不規律的移動,影響您的閱讀。這種狀況就是由於頁面上的圖像沒有定義height和width屬性而致使的。
若是沒有定義圖片的height和width屬性,那麼瀏覽器爲了可以顯示每個加載的圖像,它須要先下載圖像,而後解析出圖像的高度和寬度,並在顯示窗口留出相應的屏幕空間,這樣就會致使瀏覽器不斷地從新計算/調整頁面的佈局,這可能會延遲文檔的顯示,並致使頁面重繪。
所以,筆者建議使用<img>的 height 和 width 屬性來指定圖像的尺寸。這樣的話,瀏覽器在下載圖像以前就爲其預留出了空間,從而能夠加速文檔的顯示,還能夠避免文檔內容的移動而引發頁面重繪。
可是,須要注意的是:不要經過 height 和 width 屬性來縮放圖像。若是經過 height 和 width 屬性來縮小圖像,那麼用戶就必須下載大容量的圖像(即便圖像在頁面上看上去很小)。正確的作法是,在網頁上使用圖像以前,應該經過軟件把圖像處理爲合適的尺寸。固然,這個準則在實際應用中也有例外,例如筆者就認爲,小比例的圖像縮放應該是容許的,此外,若是頁面上須要加載同一張圖像的不一樣尺寸的顯示,由於瀏覽器對同一個圖像只會請求一次,所以此時就建議使用height 和 width 屬性來縮放圖像。
問題4:<img>標籤的onload/onerror/onabort事件,在什麼狀況下會被觸發?
onload: 事件會在圖像加載完成後當即發生。
onerror: 事件會在文檔或圖像加載過程當中發生錯誤時被觸發。
onabort: 事件會在圖像加載被中斷時發生。例如用戶單擊了瀏覽器的Stop按鈕,或者在圖像下載的過程當中。
上面的三句話雖然看起來很簡單,但實際上有許多細節須要進一步的研究,尤爲是onload和onerror事件。這些細節的問題,將在問題5中提出。
問題5:咱們通常知道,當一個圖片請求返回404時,會觸發onerror事件,那當圖片請求返回302時,會觸發onerror事件嗎?304呢?403呢?500呢?請求超時呢?甚至說當返回200,但內容並不是是圖片時,也會觸發onerror麼?
這些問題須要動手作個試驗。試驗的結果以下表所示:
圖片請求 |
觸發的事件類型 |
IE |
FireFox |
Chrome |
返回404 |
onerror |
√ |
√ |
√ |
返回302,而且跳轉地址爲一個正常的圖片 |
onload 所觸發的事件類型與原始的請求無關,而是與跳轉地址相關。 |
√ |
√ |
√ |
返回304,而且緩存生效 |
onload 但也要注意,若是緩存不存在,僅僅是單純地返回304,依然會觸發onerror |
√ |
√ |
√ |
返回403 |
onerror |
√ |
√ |
√ |
返回500 |
onerror |
√ |
√ |
√ |
請求超時 |
onerror 返回504 |
√ |
√ |
√ |
返回200,但返回的內容並不是圖片 |
onerror |
√ |
√ |
√ |
問題6:圖片觸發onerror事件時,能使用javascript獲取到圖片請求的響應代碼麼?
很遺憾,目前瀏覽器廠商還沒有提供相關的接口。
問題7:咱們通常知道,<img>標籤能夠用來發起跨域請求,你能手寫出一段正確使用<img>發起跨域請求的javascript函數麼?
這個問題看起來很簡單,或許你很快的就寫出瞭如下代碼:
1 function setImageSrc() { 2 var i = new Image(); 3 i.src = "http://.../1.gif"; 4 i.onload = function() { 5 // do sth. 6 }; 7 8 i.onerror = function() { 9 // do sth. 10 } 11 12 i.onabort = function() { 13 // do sth. 14 } 15 }
代碼中新建了一個image對象,並綁定了onload, onerror, onabort三個事件處理函數。
但實際上,上述代碼存在幾個問題,你能看出幾個呢?
1) 屬性src賦值操做應該在事件綁定以後:不然,有可能出現圖片已經加載完畢、但事件綁定還沒有完成的狀況。例如,在上述代碼片斷中,若是在第三行和第四行之間增長一句alert(1),就能重現這種狀況。
2) 在IE6中,上述事件綁定代碼會造成一個循環引用——Image對象的onload屬性引用了一個匿名函數對象,而匿名函數經過其做用域鏈引用會Image對象,這種循環引用會在IE6中致使內存泄露。所以,在onload的匿名函數中,應該解除循環引用,正確的代碼相似於:
1 i.onload = function() { 2 // do sth. 3 4 i.onload = null; 5 i = null; 6 }
3) 在IE6中,若是圖片是多幀的gif,會觸發屢次的onload事件。所以,爲避免這種狀況,也須要在onload事件處理函數中解除事件函數:
1 i.onload = function() { 2 // do sth. 3 4 i.onload = null; 5 i = null; 6 }
問題8:用戶是能夠設置瀏覽器不顯示圖片的,尤爲是在移動設備上,用戶爲了節省流量,每每會禁止圖片顯示。那麼,如何獲知用戶是否禁止瀏覽圖片呢?
注:該問題的解決方案來源於 http://stackoverflow.com/questions/8379156/how-to-detect-if-images-are-disabled-in-browser,筆者對其中的原理和代碼bug作了相應的解讀和修復。
在Firefox和Chrome中,可使用Image對象的complete屬性來解決此問題:設置Image對象的src屬性,以請求一個不存在的圖片,當瀏覽器禁止顯示圖片時,Image對象的complete屬性爲true,不然爲false。
在Opera中,也可使用Image對象的complete屬性,但它與Firefox和Chrome的不一樣,設置Image的src後,在onload以前,它一直顯示爲false。但咱們能夠將圖片的src設置爲一個特殊的值:img.src = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw=="; 這樣,當Opera禁止顯示圖片時,Image的complete屬性爲false,不然爲true。
而在IE中,Image的complete屬性會一直爲false。所以,但咱們注意到,當IE禁止顯示圖片時,是不會觸發Image對象的onload/onerror/onabort事件的。針對該特性,咱們使用setTimeout函數,當在必定的時間內沒有檢測onload/onerror/onabort事件的發生,則認爲瀏覽器禁止顯示圖片。
具體的代碼以下:
1 <script type="text/javascript"> 2 detectImageEnabledMode({ 3 onDetectImageIsDisabled:function(){ 4 alert('disabled'); 5 }, 6 onDetectImageIsEnabled:function(){ 7 alert('enabled'); 8 } 9 }); 10 11 // 用來檢測瀏覽器是否禁止顯示圖片 12 // 參數options: onDetectImageIsDisabled,檢測到禁止顯示圖片後的回調函數;onDetectImageIsEnabled, 檢測到顯示圖片後的回調函數 13 function detectImageEnabledMode(options){ 14 /* define disabled/enabled actions */ 15 var actionCounter = 0; 16 var enabledAction = options.onDetectImageIsEnabled || function() {}; 17 var enaledActionRun = function(){ 18 if(actionCounter) 19 return; 20 actionCounter++; 21 enabledAction(); 22 } 23 24 var disabledAction = options.onDetectImageIsDisabled || function(){}; 25 var disabledActionRun = function(){ 26 if(actionCounter) return; 27 actionCounter++; 28 disabledAction(); 29 } 30 31 /* create image */ 32 var img = new Image(); 33 var currentTime = (+new Date); 34 if(navigator.appName.indexOf('Microsoft Internet Explorer') != -1){// ie 35 img.onload = i.onerror = i.onabort = enaledActionRun; 36 37 // 試圖訪問一個不存在的圖片 38 img.src = currentTime+'.'+currentTime+'?time='+currentTime; 39 // 若是500毫秒後,還沒有觸發圖片的onload/onerror/onabort事件,則認爲瀏覽器禁止了圖片顯示 40 setTimeout(function(){ 41 disabledActionRun(); 42 }, 500); 43 }else if (navigator.appName.indexOf('Opera') != -1) {// opera 44 img.src = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw=="+'?time='+currentTime; 45 46 // 禁止圖片顯示時,img.complete==false 47 if(img.complete){ 48 enaledActionRun(); 49 }else{ 50 disabledActionRun(); 51 } 52 }else{// firefox chrome safari 53 // 試圖訪問一個不存在的圖片 54 img.src = currentTime+'.'+currentTime+'?time='+currentTime; 55 56 // 禁止圖片顯示時,img.complete==true 57 if(img.complete){ 58 disabledActionRun(); 59 }else{ 60 enaledActionRun(); 61 } 62 } 63 } 64 </script>
至此,相信你已經對Image有了更進一步的瞭解了。事實上,還有與Image相關的許多技巧在本文沒有說起,例如Image的lazyload。你們在實際編程中能夠慢慢接觸和了解。在之後的文章中,我也會根據實際狀況持續地寫一些與Image相關的文章。