一步步教你實現彈出窗口(第1部分)
在藍色理想看到一個漂亮的彈出層,不過看不慣其代碼,決定自己重寫一個。漂亮是有代價,它用了許多圖片,而且那是半透明圖片,這在IE6中就遇到麻煩,需要動用IE的DXImageTransform.Microsoft.AlphaImageLoader來實現fixbug!對于我而言,圖片根本是沒有必要,因為我掌握非常先進的動態生成圖片(位圖)的技術,這樣就可以大大減少請求數與圖片對服務器的壓力。但是,該死的IE6不支持這種技術,因此我還是需要一些圖片。至于半透明與圓角與陰影,我是利用vml與canvas與CSS3高級特征來實現。好了,開場白就此打住,我們開始吧。
通常而言,彈出窗口都是居中對齊的,因此我們需要獲取瀏覽器可視區的大小。這里有一個函數,可以幫我們迅速取得結果。
var getBrowserWindowSize = function(){ var de = document.documentElement; return { 'width':( window.innerWidth || (de && de.clientWidth ) || document.body.clientWidth), 'height':( window.innerHeight || (de && de.clientHeight ) || document.body.clientHeight) } }
要創建一個彈出窗口,我們需要一些參數,具體可以參考這里。但作為起步,我們不需要面面俱到,現在只要title,width與height這三個就算了。以下是其主體框架:
var Dialog = function(){ var options = arguments[0] || {}; this.title = options.title || "新窗口", this.width = options.width || 400, this.height = options.height || 300, this.contain = document.createElement("div"), this.id = "id" + (( new Date() * Math.random()) >> 0); this.init(); } Dialog.prototype = { constructor: Dialog, init: function() { //***************** } }
UI控件就難免涉及動態設置樣式的問題,通常人們都是這樣做:el.style.cssText = "******************"
換言之,就是使用內聯樣式。但這樣做有兩個缺點:1,不能使用偽類;2,相同樣式容易重復定義。我的一個腳本雖然也用到cssText,但生成的是內部樣式,完美地避免了這兩個問題。我早期的UI控件都是利用它來設置樣式。不過,如你們所見,它的體積比較龐大,而且一下子設置所有樣式,需要對UI有夠全面的了解,在迭代開發中,恐怕沒有人敢保證他現在寫的樣式就是最后確定用的樣式。因此,我又開發另一套動態設置樣式規則的方法。IE有一個很好用的方法,createStyleSheet,能生成一個樣式表對象。不過有個缺陷,就是一個頁面只能使用31次,再多就只能求助于document.createElement("style")。IE的樣式表對象有兩個重要的方法,分別為addRule與removeRule 。我是不推薦用removeRule方法,同理,任何移除節點的方法能不用就不要用。因為IE7中,引入新的DOM元素的回收機制:在離開頁面時回收DOM樹上的所有元素。換言之,如果所有元素(無論動態創建的還是原來的),只要關閉引頁面時,它們都在DOM樹上,就不會泄漏,否則肯定泄漏。你不要以為當時移除節點后,IE7會即時回收它,對不起,它很懶,因此內存會一直飆升,直到關閉時才得以喘息。回歸正傳,標準瀏覽器肯定沒有這些方法,對應方法都是非常不好用,因此我們讓它們擁有這種IE風格的方法即可。
if(typeof document.createStyleSheet === 'undefined') { document.createStyleSheet = (function() { function createStyleSheet() { var element = document.createElement('style'); element.type = 'text/css'; document.getElementsByTagName('head')[0].appendChild(element); var sheet = document.styleSheets[document.styleSheets.length - 1]; if(typeof sheet.addRule === 'undefined') sheet.addRule = function(selectorText, cssText, index) { if(typeof index === 'undefined') index = this.cssRules.length; this.insertRule(selectorText + ' {' + cssText + '}', index); }; return sheet; } return createStyleSheet; })(); }
然后我們用createStyleSheet創建一個樣式表對象,并把作為Dialog的靜態屬性, 目的讓所有Dialog對象都共享這個對象,因為在IE中,這方法在一個頁面只能使用31次, 能省就省啊!
if(!!Dialog.sheet){
Dialog.sheet.addRule(selector,declaration);
}else{
Dialog.sheet = document.createStyleSheet();
Dialog.sheet.addRule(selector,declaration);
}
這有點像單例模式,但上面的寫法只能保證創建一個樣式表對象,不能防止兩個完全一樣的樣式規則對象的創建。有關樣式規則對象等概念,請參考我另一篇博文《再談動態添加樣式規則》。
在IE8開發人員工具下,我們可以看到一些樣式規則完全一樣。我的設想是選擇器部分可以重復,但其內容不能重復。因此我們需要設置一個容器來保存與管理這些樣式規則。

初步開發了這樣一個小東西,類似java的集合,但去掉無關的功能:
var memory = function(){ var keys = [],values = [],size = 0; return { get : function(k){ var results = []; for(var i=0,l=keys.length;i
我們把它整合到Dialog類中,這樣就可以防止冗余重復的CSS代碼生成了!

至此,Dialog類的輔助方法就準備得差不多了,下一部分將正式進行開發。