圖片的預加載就是在加載大圖片前,先顯示一個loading.gif,就算在網絡比較慢的時候也能讓人知道正在加載,總比啥反應都沒有強。
下面這段代碼就是預加載的一個簡單的實現,假設先不處理加載圖片時的onError,onAbort,超時的問題。
只關注代碼的結構。
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> </head> <body> <button id='btnLoadImg'>加載圖片</button> <br> <div id='imgContainer'> </div> <br> <script type='text/javascript' src="./jquery-1.11.3.min.js"></script> <script type='text/javascript'> $(document).ready(function(){ $('#btnLoadImg').bind('click', doLoadImg); }); function doLoadImg(){ var eleImg = createImgElement(); document.getElementById('imgContainer').appendChild(eleImg); loadImg(eleImg, 'http://img.wanchezhijia.com/A/2015/3/20/17/11/de63f77c-f74f-413a-951b-5390101a7d74.jpg'); } //創建img標簽 //這里用自執行函數加一個閉包,是為了可以創建多個id不同的img標簽。 var createImgElement = (function(){ var index = 0; return function() { var eleImg = document.createElement('img'); eleImg.setAttribute('width', '200'); eleImg.setAttribute('heght', '150'); eleImg.setAttribute('id', 'img' + index++); return eleImg; }; })(); //預加載圖片 //給img標簽設一個加載圖片,通過Image對象預先加載實際圖片加載完成后設到img標簽上 function loadImg(img, src) { var imgCache = new Image(); imgCache.onload = function(){ img.src = this.src; }; img.src = 'loading.gif'; imgCache.src = src; } </script> </body> </html>
以下預加載的代碼功能上是滿足了,但是它的職責包含了預加載和加載兩個職責,違反了“單一職責原則”。所謂的職責就是“會發生的變化”,如果網速的問題不再是問題或者加載的圖片的分辨率被控制在很小的時候等,需要去掉預加載的功能,這時候就要修改loadImg的代碼,就要重新跑所有相關的測試,即違反了“開閉原則”,又增加測試工作。
function loadImg(img, src) { var imgCache = new Image(); imgCache.onload = function(){ img.src = this.src; }; img.src = 'loading.gif'; imgCache.src = src; }
加載和預加載其實就是代理模式的一種,代理模式可以理解成,你會開車但是因為某種原因只能找人代理開車,因為不了解MM的喜好找人代理送花。
將預加載功能改成代理模式可以理解成:本體先顯示個門面,找代理去加載,加載完了,告訴本體,本體把圖片貼上去就行了。
既然如此,本體的職責就很簡單了,就往門面上貼。
加載本體函數:
function loadImg(img, src) { img.src = src; }
做一個預加載代理函數:
function loadImgProxy(img, src){ var imgCache = new Image(); imgCache.onload = function(){ loadImg(img, this.src); }; loadImg(img, 'loading.gif'); imgCache.src = src; }
在代理函數中,先讓本體加載loading.gif,等大圖加載完了再讓本體加載實際圖片。
代理還是和本體函數的接口參數是一致的,職責分的比較清晰,如果到時候要把預加載去掉,也不需要修改本體和代理的代碼,只需要在調用的地方把代理的名字換成本體的名字即可。
可以適當的把代理函數改一下,可以讓其適應加載多個圖片的場景,其實就是做一個閉包,把緩存Image對象變成私有即可:
var loadImgProxy = (function(){ var imgCache = new Image(); return function(img, src){ imgCache.onload = function(){ loadImg(img, this.src); }; loadImg(img, 'loading.gif'); imgCache.src = src; }; })();
修改后的完整代碼:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> </head> <body> <button id='btnLoadImg'>加載圖片</button> <br> <div id='imgContainer'> </div> <br> <script type='text/javascript' src="./jquery-1.11.3.min.js"></script> <script type='text/javascript'> $(document).ready(function(){ $('#btnLoadImg').bind('click', doLoadImg); }); function doLoadImg(){ var eleImg = createImgElement(); document.getElementById('imgContainer').appendChild(eleImg);
//使用代理函數進行加載
//如果某一天不需要預加載了,就把loadImgProxy換成loadImg即可 loadImgProxy(eleImg, 'http://img.wanchezhijia.com/A/2015/3/20/17/11/de63f77c-f74f-413a-951b-5390101a7d74.jpg'); } //創建img標簽 //這里用自執行函數加一個閉包,是為了可以創建多個id不同的img標簽。 var createImgElement = (function(){ var index = 0; return function() { var eleImg = document.createElement('img'); eleImg.setAttribute('width', '200'); eleImg.setAttribute('heght', '150'); eleImg.setAttribute('id', 'img' + index++); return eleImg; }; })();
//加載圖片本體函數 function loadImg(img, src) { img.src = src; }
//加載圖片代理函數 var loadImgProxy = (function(){ var imgCache = new Image(); return function(img, src){ imgCache.onload = function(){ loadImg(img, this.src); }; loadImg(img, 'loading.gif'); imgCache.src = src; }; })(); </script> </body> </html>