Pro JavaScript Techniques第七章: JavaScript與CSS
JavaScript和CSS的交互是現代JavaScript程序設計的支柱。事實上對於所有的現代web應用程序來說,至少使用某些形式的動態交互是必須的。那麼做過之後,用戶可以更快地操作而更少地把時間浪費在等待頁麵加載上。將動態技術與第六章提出的事件方麵的觀念相結合,對於實現無縫而強大的用戶體驗是非常重要的。
層疊式樣式表是用來對易用的、有吸引力的網頁進行修飾和布局的事實標準,它在給用戶提供最少的困難的同時為開發者提供最多的能力。當你將那一能力與JavaScript相結合時,你將能夠構造強健的用戶界麵,包括動畫、窗口部件(widgets),或動態顯示等。
訪問樣式信息
JavaScript與CSS的結合全部是以表現作為結果的交互。理解什麼對你是可用的,對於精確地達到你想要的交互非常重要。
用來設置和獲取元素的CSS屬性的主要工具是其style屬性。比如說,如果想要取得一個元素的高度,你可以編寫如下代碼:elem.style.height。如果你想要設置元素的高度為某個特定值,你可以執行如下代碼:ele.style.height="100px"。
當處理DOM元素的CSS屬性時,有兩個會碰到的問題,它們並不像一般人所期望的那樣運作。首先,JavaScript要求你在設置任何空間尺度時指明單位(就像前麵設置高度時所做的那樣)。同時,任何空間屬性也將返回一個代表元素屬性的字符串而非數字(如"100px"而非100)。第二,如果一個元素高為100像素,而你試圖獲取它的當前高度,你期望從style屬性裏取得那個"100px",情況卻未必會如你所願。這是因為任何樣式表文件或內聯CSS預設的樣式信息並不能可靠地反映到style屬性上。
這一狀況將我們引向JavaScript中處理CSS的一個重要函數:獲取一個元素真正的當前樣式屬性的方法,給你一個預期的精確值。存在一組(來源於W3C和IE特有的變種)相當可靠的方法可以用來得到DOM元素的真正的計算後的樣式屬性。它們能顧及所有相關的樣式表、元素特定屬性以及JavaScript所作的修改。當需要得到你正操作的元素的精確視圖信息時這些方法將會是極其有用的。
獲取元素的計算後樣式值時應該考慮到存在於不同的瀏覽器間的大量的差異。跟在大多數的情形一樣,IE有它自己的方法,而其它所有的瀏覽器都使用W3C定義的方式來實現。
程序7-1給出了一個用來找出元素的計算後樣式屬性值的一個函數,7-2則給出了使用此函數的一個示例。
程序7-1. 用來得到元素的計算後的實際CSS樣式值的一個函數
CODE:
function getStyle( elem, name ) {
//如果該屬性存在於style[]中,則它最近被設置過(且就是當前的)
if (elem.style[name])
return elem.style[name];
//否則,嚐試IE的方式
else if (elem.currentStyle)
return elem.currentStyle[name];
//或者W3C的方法,如果存在的話
else if (document.defaultView && document.defaultView.getComputedStyle) {
//它使用傳統的"text-Align"風格的規則書寫方式,而不是"textAlign"
name = name.replace(/([A-Z])/g,"-$1");
name = name.toLowerCase();
//獲取style對象並取得屬性的值(如果存在的話)
var s = document.defaultView.getComputedStyle(elem,"");
return s && s.getPropertyValue(name);
//否則,就是在使用其它的瀏覽器
} else
return null;
}
<head>
<style>p { height: 100px; }</style>
<script>
window.onload = function(){
//找到欲檢查高度的段落對象
var p = document.getElementsByTagName("p")[0];
//使用傳統方式檢查其高度
alert( p.style.height + " should be null" );
//檢查計算後的高度值
alert( getStyle( p, "height" ) + " should be 100px" );
};
</script>
</head>
<body>
<p>I should be 100 pixels tall.</p>
</body>
</html>
動態元素的隱含的意思也就是使用JavaScript和CSS維護或創建的非靜態的元素。簡單的例子是指示你對時事通訊感興趣的複選框和彈出式的e-mail輸入域。
在最基本的層麵上,有三個關鍵的屬性可用來構造動態效果:位置、尺寸、可見性。使用這三個屬性你可以在現代瀏覽器上模擬大多數常見的用戶交互效果。
元素的位置
操作元素的位置是在頁麵中開發動態元素的一個重要構成部分。訪問和修改CSS位置屬性讓你有效地模擬許多流行的動畫和交互效果(比如拖放)。
知道CSS的定位係統是怎樣工作是操作元素位置的一個重要步驟。在CSS中,元素使用偏移來定位,使用的度量是相對父元素的左上角的偏移量。圖7-1是CSS中使用的坐標係統的一個例子。
[attach]37002[/attach]
圖7-1. 使用CSS的網頁裏坐標係統示例
頁麵上的所有元素都有著某種形式的top(垂直坐標)和left(水平坐標)偏移。大體來說,多數元素簡單地根據其周圍的元素靜態定位。依照CSS標準的提議,一個元素可以有幾種不同的定位方案。為了正好地理解這一點,我們來看看程序7-3所示的一個簡單的網頁。
<head>
<style>
p {
border: 3px solid red;
padding: 10px;
width: 400px;
background: #FFF;
}
p.odd {
/* Positioning information goes in here */
position: static;
top: 0px;
left: 0px;
}
</style>
</head>
<body>
<p>Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Etiam …p>
<p class='odd'>Phasellus dictum dignissim justo. Duis nec risus id nunc…p>
<p>Sed vel leo. Nulla iaculis, tortor non laoreet dictum, turpis diam …</p>
</body>
</html>
靜態定位: 這是元素定位的默認方式;它簡單地遵從文檔的自然流向。當一個元素靜態定位時,top和left屬性將不起作用。靜態定位的一個例子見圖7-2,其中用於定位的css為:position:static;top:0px;left:0px。
[attach]37003[/attach]
圖7-2. 頁麵正常(static)布局流裏的段落
相對定位: 這一定位方式與靜態定位非常相似,因為元素仍然會遵循正常的文檔流直到得到其它指示。但是,設置top或left屬性將會導致元素相對它的原來的(靜態的)位置發生偏移。相對定位的一個例子如圖7-3所示,其中的CSS定位為position:relative;top:-50px;left:50px。
[attach]37004[/attach]
圖7-3. 相對定位,元素被移位到了前一個元素上麵,而不再遵循正常的文檔流
絕對定位: 將一個元素完全從正常的頁麵布局流中抓出來。被絕對定位的元素將相對於其第一個非靜態定位的父級元素來顯示。如果不存在父元素,它將相對於整個文檔被定位。絕對定位的一個例子見圖7-4,其中用於定位的css為:position:absolute;top:20px;left:0px。
[attach]37005[/attach]
圖7-4. 絕對定位,元素的位置與頁麵的左上角相關,顯示在已經存在的元素之上
固定定位: 固定定位將一個元素相對於瀏覽器的窗口定位。設置一個元素的top和left為0相素,將會使得該元素顯示在瀏覽器的左上角(隻要用戶還在那個頁麵上),完全忽略瀏覽器滾動條的任何動作。固定定位的一個例子見圖7-5,其中用於定位的css為:position:fixed;top:20px;right:0px。
[attach]37006[/attach]
圖7-5. 固定定位,元素被定位到頁麵的右上角,盡管瀏覽器窗口被向下滾動了。
取得位置
元素被定位在何處依賴於它的css參數以及與其鄰接的內容而不同。訪問CSS屬性或計算後的實際值都沒有提供的一個能力是,獲取元素在頁麵中或者僅在其它元素中的確切位置。
首先,我們來看如何獲取元素在頁麵中的位置。你擁有幾個可支配的元素屬性可用來找到這一信息。所有的現代瀏覽器都支持以下三個屬性;當然它們各自是怎麼處理的,又是另外一回事了:
offsetParent: 理論上,這是元素在其中定位的父級元素。但是在實際情況下,offsetParent引用的元素取決於瀏覽器(比如說,在FireFox中,它引用根節點,而在Opera中,則是直接父元素。
offsetLeft和offsetTop: 這些參數是元素在其offsetParent上下文中的水平和垂直偏移。在現代瀏覽器上,它總是精確的。
現在,問題在於尋求一種可以跨瀏覽器工作的用來判定方式元素位置的一致的辦法。實現這一點的最一致的辦法如程序7-4所示:使用offsetParent屬性沿著DOM樹上行,一路累加偏移值。
程序7-4. 計算元素相對於文檔的x和y坐標的輔助函數
function pageX(elem) {
//檢查我們是否已經到了根元素
return elem.offsetParent ?
//如果我們還能往上,則將當前偏移與向上遞歸的值相加
elem.offsetLeft + pageX( elem.offsetParent ) :
//否則,取當前偏移
elem.offsetLeft;
}
//計算元素的Y(垂直,頂)位置
function pageY(elem) {
//檢查我們是否已經到了根元素
return elem.offsetParent ?
//如果我們還能往上,則將當前偏移與向上遞歸的值相加
elem.offsetTop + pageY( elem.offsetParent ) :
//否則,取當前偏移
elem.offsetTop;
}
使用元素相對於其父元素的位置,你可以向DOM添加額外的相對該父元素定位的元素。比如,這個值用來建造上下文相關的工具提示是非常理想的。
為了找到元素相對於其父元素的位置,你必須再一次求助於offsetParent屬性。因為該屬性並不能保證返回特定元素的實際的父元素,你不得不使用你的pageX和pageY函數來找到父元素與子元素之間的位置差異。在程序7-5所示的兩個函數中,我試圖首先使用offsetParent,如果它是當前元素的實際的父元素;否則,我將繼續使用pageX和pageY方法沿DOM上行,以確定它的實際位置。
程序7-5. 用來確定元素相對於其父元素位置兩個函數
function parentX(elem) {
//如果offsetParent就是元素的parent,則提前返回
return elem.parentNode == elem.offsetParent ?
elem.offsetLeft :
//否則,我們需要找出兩個元素相對整個頁麵的位置,計算差值
pageX( elem ) - pageX( elem.parentNode );
}
//查找元素在其父元素中的垂直位置
function parentY(elem) {
//如果offsetParent就是元素的parent,則提早返回
return elem.parentNode == elem.offsetParent ?
elem.offsetTop :
//否則,我們需要找出兩個元素相對整個頁麵的位置,計算差值
pageY( elem ) - pageY( elem.parentNode );
}
有兩個可用的簡單的包裝函數可以處理這一點,如程序7-6所示。它們都隻是簡單調用getStyle函數,但同時也刪除任何多餘的(除非你不是使用基於像素的布局,它才是有用的)單位信息(比如說,100px將變成100)。
程序7-6. 找出元素的CSS定位的輔助函數
function posX(elem) {
//取得計算後樣式並從中提取數字
return parseInt( getStyle( elem, "left" ) );
}
//得到元素的top位置
function posY(elem) {
//取得計算後的樣式並從中提取數字
return parseInt( getStyle( elem, "top" ) );
}
設置元素位置
不同於取得元素的的位置,設置位置要少許多變數。但是聯合使用各種方式的布局(absolut,relative,fixed)時,你將能得到相當的、可用的結果。 目前,調整元素位置的唯一的辦法是通過修改它的CSS屬性。為了保持方法上的一致性,你應該僅修改left和top屬性,盡管存在著其它的屬性(如bottom和top)。作為開端,你可以輕鬆地創建一對函數,如程序7-7所示,用來設置一個元素的位置,而不考慮其當前位置。 程序7-7. 不考慮其當前位置,設置元素的x和y位置的一對函數
CODE:
//設置元素垂直位置的一個函數
function setX(elem, pos) { //使用像素為單位,設置CSS屬性'left' elem.style.left = pos + "px"; } //設置元素水平位置的一個函數 function setY(elem, pos) { //使用像素為單位,設置CSS屬性'top' elem.style.top = pos + "px"; } 最終,你需要開發第二套函數,如程序7-8所示,你可以用它們來設置一個元素相對於其原來的位置的位置——比如,調整一個元素使其水平位置比當前值小5個像素。這一方法的使用直接與許多作為DHTML開發的支柱的動畫效果相關。 程序7-8. 用來調整元素相對於基原來的位置的一對函數
CODE:
//用來把元素的水平位置增加幾個像素的一個函數
function addX(elem,pos) { //取得當前的水平位置並向其加入偏移 setX( posX(elem) + pos ); } //用來把元素的垂直位置增加幾個像素的一個函數 function addY(elem,pos) { //取得當前的垂直位置並向其加入偏移 setY( posY(elem) + pos ); } 現在我已經將處理元素位置的問題完全貫串了一遍。理解元素定位怎樣工作和怎麼設置及獲取元素的精確位置是處理動態元素的一個基本的方麵。你將看到的下一個側麵是元素的確切尺寸。 元素的尺寸 計算元素的高度和寬度可能是既無比簡單又痛苦的一件事,這取決於具體的情況和你需要它做什麼。許多情況下,你隻需要使用getStyle函數的一個修改版本來得到元素的當前寬度和高度,如程序7-9所示。 程序7-9. 檢索DOM元素的當前高度和寬度的兩個函數
CODE:
//獲取元素的實際高度(使用計算後的CSS)
function getHeight( elem ) { //取得計算後的CSS值並解析出一個可用的數字 return parseInt( getStyle( elem, 'height' ) ); } //獲取元素的實際寬度(使用計算後的CSS) function getWidth( elem ) { //取得計算後的CSS值並解析出一個可用的數字 return parseInt( getStyle( elem, 'width' ) ); } 當你試圖做這兩件事的時候麻煩就來了:第一,當你想要得到元素預定義的完整高度(比如說,你將一個動畫從0px開始,但你需要知道該元素應該到達多高多寬),第二,當一個元素的display設為"none"時,你將取不到值。 程序7-10裏給出的兩個函數說明了怎樣找出元素潛在的完整高度和寬度,不論它當前的高度是多少。這是通過訪問clientWidth和clientHeight屬性實現的,它們提供元素能夠展開到的可能的總的區域。 程序7-10. 用來找出元素的潛在高度和寬度的兩個函數,即使元素是隱藏的
CODE:
//找出元素完整的、可能的高度(不是實際的、當前的高度)
function fullHeight( elem ) { //如果元素當前是顯示的,那麼offsetHeight應該可以成功,即使失敗,getHeight也可以生效 if ( getStyle( elem, 'display' ) != 'none' ) return elem.offsetHeight || getHeight( elem ); //否則,我們必須處理display為'none'的元素, //這時我們需要重置它的CSS屬性以得到更精確的讀數 var old = resetCSS( elem, { display: '', visibility: 'hidden', position: 'absolute' }); //計算元素的完整高度,如果clientHeight無效,則用getHeight() var h = elem.clientHeight || getHeight( elem ); //最後,我來來恢複元素本來的CSS屬性 restoreCSS( elem, old ); //並返回元素的完整高度 return h; } //找出元素完整的、可能的寬度(不是實際的、當前的寬度) function fullWidth( elem ) { //如果元素當前是顯示的,那麼offsetWidth應該可以成功,即使失敗,getWidth也可以生效 if ( getStyle( elem, 'display' ) != 'none' ) return elem.offsetWidth || getWidth( elem ); //否則,我們必須處理display為'none'的元素, //這時我們需要重置它的CSS屬性以得到更精確的讀數 var old = resetCSS( elem, { display: '', visibility: 'hidden', position: 'absolute' }); //計算元素的完整寬度,如果clientWidth無效,則用getWidth() var w = elem.clientWidth || getWidth( elem ); //最後,我來來恢複元素本來的CSS屬性 restoreCSS( elem, old ); //並返回元素的完整寬度 return w; } //用來設置一係列的CSS屬性的一個函數,這些屬性稍後可以恢複 function resetCSS( elem, prop ) { var old = {}; //遍曆每一個屬性 for ( var i in prop ) { //記錄原來的屬性 old[ i ] = elem.style[ i ]; //並設置新的值 elem.style[ i ] = prop[i]; } //返回改變的值的集合,以備restoreCSS使用 return old; } //恢複resetCSS函數引用的副作用的函數 function restoreCSS( elem, prop ) { //將所有的屬性重新設置為它們原來的值 for ( var i in prop ) elem.style[ i ] = prop[ i ]; } 同時擁有了取得元素當前的和潛在的寬度與高度的能力,你可以使用這些值來開發出一些你能夠達到的動畫。但是,在我進入動畫的細節之前,你還需要看看怎樣修改元素的可見性。 元素的可見性 元素的可見性是可在JavaScript中用來創建從動畫到快速模板效果的每一樣東西的強大工具。然而,更重要的是,它也能用來從視圖中快速地隱藏元素,提供一些基本的用戶界麵功能。 在CSS裏有兩種不同的方式來有效地從視圖中隱藏元素;它們各自有其益處但也能產生無意的後果,這取決於你怎樣使用它們: ◇ visibility屬性決定一個元素是否可見,同時仍保持它在布局流中的正常占位。visibility屬性有兩個值:visible(缺省值)和hidden(使一個元素完全不可見)。比如說,如果你有一些<b>標簽中換行的visibility屬性設為hidden的文本,結果將簡單地顯示為文本中的一個空白塊,尺寸與原始文本完全相同。例如,比較以下兩行文本: //正常文本: Hello John, how are you today? //對"John"應用了"visibility:hidden"的文本 Hello , how are you today? ◇ display屬性為開發者提供了更多的選項來控製元素的而局。這些選項是inline(類似於<b>和<span>的標簽是行內的,也就是說他們遵循正常的文本流布局),block(類似於<p>和<div>的標簽是塊級的,他們打破正常的文本流),和none(從文檔中徹底隱藏元素)。將display屬性設為none的結果表麵上跟你把它從文檔中刪除完全一致;然而,實情並非那樣,因為它可以在遲些時候快速地被切換回視圖裏。下麵的兩說明了display屬性是怎樣工作的: //正常文本: Hello John, how are you today? //對"John"應用了"display:none"的文本 Hello , how are you today? 盡管visibility屬性有它的特定的用途,display屬性的重要性不容忽視。元素的visibility屬性被設為hidden時它仍存在於正常的文本流中,這使用得在許多應用中visibility的可行性打了折扣。程序7-11中展示了使用display屬性來切換元素可見性的兩種方法。 程序7-11. 使用CSS Display屬性來切換元素的可見性的一組函數
CODE:
//用來(使用display)隱藏元素的一個函數
function hide( elem ) { //找到元素的當前顯示狀態是什麼 var curDisplay = getStyle( elem, 'display' ); //記錄它的顯示狀態 if ( curDisplay != 'none' ) elem.$oldDisplay = curDisplay; //將display設為none(隱藏元素) elem.style.display = 'none'; } //用來(使用display)顯示元素的函數 function show( elem ) { //將display屬性設為它曾經的值,或者使用'',如果沒有保存過先前的display的話 elem.style.display = elem.$oldDisplay || ''; } 可見性的另一麵是元素的透明度。調整元素透明度產生的結果與設置元素的visibility非常相似,但是了對元素有多可見的更好的控製。這意味著你可以使一個元素50%可見,使得你可以看到在它下麵的元素。所有的現代瀏覽器都在一定程度上支持透明度,IE和W3C兼容的瀏覽器再一次在實現方式上有著不同。為了解決這一問題,你可以建創一個標準的函數用來維護元素的透明度,如7-12所示。level為0表示著元素是完全透明的,而level為100表示完全不透明。 程序7-12. 調整元素的透明度級別的一個函數
CODE:
//設置元素的透明度級別(level是0-100的數字)
function setOpacity( elem, level ) { //如果濾鏡存在,這是IE,於是設置Alpha濾鏡 if ( elem.filters ) elem.style.filter = 'alpha(opacity=' + level + ')'; //譯注:此處原文為ele.style.filters='alpha(opacity=' + level + ')',有誤 //多謝02062007同學的熱心驗證 //否則,使用W3C的opacity屬性 else elem.style.opacity = level / 100; } 掌握了調整元素的位置、大小、及可見性的方法,是時候開始探索你聯合使用這些能力做一些有意思的事情了。 [ 本帖最後由 mozart0 於 2007-5-25 15:42 編輯 ] ![]() |
one by one
|
[廣告] 網站博客賣廣告推薦:阿裏媽媽 |
mozart0 ![]() 匪徒田老大 帖子 2326 體力 6628 威望 177 注冊 2003-6-18 |
|
mozart0 ![]() 匪徒田老大 帖子 2326 體力 6628 威望 177 注冊 2003-6-18 |
|
mozart0 ![]() 匪徒田老大 帖子 2326 體力 6628 威望 177 注冊 2003-6-18 |
|
mozart0 ![]() 匪徒田老大 帖子 2326 體力 6628 威望 177 注冊 2003-6-18 |
|