閱讀813 返回首頁    go 阿裏雲 go 技術社區[雲棲]


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:

//獲取一個特定元素(elem)的樣式屬性(name)
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;
}
程序7-2. 元素的計算後的CSS樣式值未必是style對象裏可用值的一種情況
CODE:
<html>
<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>
  程序7-2說明了怎樣得到一個DOM元素的實際的CSS屬性值。在這種情形裏你得到的是元素的實際的像素高度,即使其高度是通過頭部的CSS來設定的。應該注意的是,你的函數將會忽略度量的單位(比如使用的是百分比)。盡管這一解決方案並不是絕對安全的,它的確是一個良好的出發點。
動態的元素

  動態元素的隱含的意思也就是使用JavaScript和CSS維護或創建的非靜態的元素。簡單的例子是指示你對時事通訊感興趣的複選框和彈出式的e-mail輸入域。
  在最基本的層麵上,有三個關鍵的屬性可用來構造動態效果:位置、尺寸、可見性。使用這三個屬性你可以在現代瀏覽器上模擬大多數常見的用戶交互效果。

  元素的位置

  操作元素的位置是在頁麵中開發動態元素的一個重要構成部分。訪問和修改CSS位置屬性讓你有效地模擬許多流行的動畫和交互效果(比如拖放)。
  知道CSS的定位係統是怎樣工作是操作元素位置的一個重要步驟。在CSS中,元素使用偏移來定位,使用的度量是相對父元素的左上角的偏移量。圖7-1是CSS中使用的坐標係統的一個例子。
[attach]37002[/attach]
  圖7-1. 使用CSS的網頁裏坐標係統示例

  頁麵上的所有元素都有著某種形式的top(垂直坐標)和left(水平坐標)偏移。大體來說,多數元素簡單地根據其周圍的元素靜態定位。依照CSS標準的提議,一個元素可以有幾種不同的定位方案。為了正好地理解這一點,我們來看看程序7-3所示的一個簡單的網頁。
  程序7-3. 演示使用不同的定位方案的一個網頁
CODE:
<html>
<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>
 我們來看看在上麵這個簡單的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坐標的輔助函數
CODE:
//計算元素的X(水平,左)位置
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;
}
  定位問題的另一部分是計算元素在其父元素中的偏移。需要注意的重要的一點是,簡單地使用元素的style.left或style.top屬性是不夠的,因為你可能想要找出沒有用Javascript或CSS定義樣式的元素的位置。
  使用元素相對於其父元素的位置,你可以向DOM添加額外的相對該父元素定位的元素。比如,這個值用來建造上下文相關的工具提示是非常理想的。
  為了找到元素相對於其父元素的位置,你必須再一次求助於offsetParent屬性。因為該屬性並不能保證返回特定元素的實際的父元素,你不得不使用你的pageX和pageY函數來找到父元素與子元素之間的位置差異。在程序7-5所示的兩個函數中,我試圖首先使用offsetParent,如果它是當前元素的實際的父元素;否則,我將繼續使用pageX和pageY方法沿DOM上行,以確定它的實際位置。

  程序7-5. 用來確定元素相對於其父元素位置兩個函數
CODE:
//查找元素在其父元素中的垂直位置
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 );
}
定位問題的最後一方麵是找出元素相對於其CSS容器的位置。如前麵所討論的,元素可能實際被包含在一個元素中而相對於另一個元素被定位(通過使用相對和絕對定位)。記住這一點,你可以回頭利用getStyle函數來得出計算後的CSS偏移值,因為那正是等效的定位。
  有兩個可用的簡單的包裝函數可以處理這一點,如程序7-6所示。它們都隻是簡單調用getStyle函數,但同時也刪除任何多餘的(除非你不是使用基於像素的布局,它才是有用的)單位信息(比如說,100px將變成100)。

  程序7-6. 找出元素的CSS定位的輔助函數
//得到元素的left位置
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位置的一對函數

//設置元素垂直位置的一個函數
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. 用來調整元素相對於基原來的位置的一對函數

//用來把元素的水平位置增加幾個像素的一個函數
function addX(elem,pos) {
    //取得當前的水平位置並向其加入偏移
    setX( posX(elem) + pos );
}
//用來把元素的垂直位置增加幾個像素的一個函數
function addY(elem,pos) {
    //取得當前的垂直位置並向其加入偏移
    setY( posY(elem) + pos );
}

  現在我已經將處理元素位置的問題完全貫串了一遍。理解元素定位怎樣工作和怎麼設置及獲取元素的精確位置是處理動態元素的一個基本的方麵。你將看到的下一個側麵是元素的確切尺寸。

  元素的尺寸

  計算元素的高度和寬度可能是既無比簡單又痛苦的一件事,這取決於具體的情況和你需要它做什麼。許多情況下,你隻需要使用getStyle函數的一個修改版本來得到元素的當前寬度和高度,如程序7-9所示。

  程序7-9. 檢索DOM元素的當前高度和寬度的兩個函數

//獲取元素的實際高度(使用計算後的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. 用來找出元素的潛在高度和寬度的兩個函數,即使元素是隱藏的

//找出元素完整的、可能的高度(不是實際的、當前的高度)
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屬性來切換元素的可見性的一組函數

//用來(使用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. 調整元素的透明度級別的一個函數

//設置元素的透明度級別(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

發表於 2007-5-14 13:14  資料  短消息  加為好友  QQ
動畫

  現在你已經掌握了執行基本的DHTML操作的基本技能,我們再來看web應用程序中流行的視覺效果之一:動畫。如果使用得宜,動畫將能夠為用戶提供有用的反饋,比如將注意力引向屏幕上的新創建的元素。
  我們將先看兩個流行的動畫效果,再在研究廣泛使用的DHTML庫時重訪它們。

  滑入

  在第一個動畫裏將處理一個(display屬性為"none"的)隱藏元素,你將通過在一秒之內逐漸增加其高度來漸漸地顯示它,以取代粗糙的show()函數。程序7-13所示的函數可以用作show()函數的合適的替代,為用戶提供更加平滑的視覺體驗。

  程序7-13. 通過一在秒之內遞增其高度來慢慢顯示隱藏元素的函數

function slideDown( elem ) {
    //從0開始擴張
    elem.style.height = '0px';
    //顯示元素(但你看不到它,因為高度為零)
    show( elem );
    //得到元素的完整的潛在高度
    var h = fullHeight( elem );
    //我們將做一個在一秒鍾內播放的20"幀"的動畫
    for ( var i = 0; i <= 100; i += 5 ) {
    
        //保證我們有一個正確的i的閉包
        (function(){
            var pos = i;
            //設置未來特定時間的定時器
            setTimeout(function(){
                //設置元素的新高度
                elem.style.height = ( pos / 100 ) * h  + "px";
                }, ( pos + 1 ) * 10 );
        })();
    }
}

  淡入

  你們將看到的下一個動畫與第一個非常相似,不過用先前所創建的setOpacity()函數代替了修改高度。這一函數(如程序7-14)顯示一個隱藏的元素,並將其透明度從0(完全透明)逐漸變化到100%(完全不透明)。與7-13的函數一樣,它為用戶提供更加平滑的視覺體驗。

  程序7-13. 通過一在秒之內遞增其透明度來慢慢顯示隱藏的元素的函數

function fadeIn( elem ) {
    //透明度從零開始
    setOpacity(elem,0);
    //顯示元素(但是你看不到它,因為透明度為零)
    show( elem );
    //我們將做一個在一秒鍾內播放的20"幀"的動畫
    for ( var i = 0; i <= 100; i += 5 ) {
    
        //保證我們有一個正確的i的閉包
        (function(){
            var pos = i;
            //設置未來特定時間的定時器
            setTimeout(function(){
                //設置元素的新的透明度
                setOpacity(elem,pos);
                }, ( pos + 1 ) * 10 );
        })();
    }
}

[ 本帖最後由 mozart0 於 2007-6-20 08:54 編輯 ]

頂部
one by one
mozart0

匪徒田老大



帖子 2326
體力 6628
威望 177
注冊 2003-6-18

發表於 2007-5-14 13:14  資料  短消息  加為好友  QQ
瀏覽器

  除了操作特定的DOM元素以外,懂得怎樣修改或追蹤瀏覽器及其部件,將大大提升站點與用戶間的交互。與瀏覽器協同工作最重要的兩個方麵是判定鼠標的位置和及用戶將頁麵滾動了多少。

  鼠標位置

  獲取鼠標位置是為用戶提供拖放操作和上下文菜單的基本要求,這兩種效果都隻能通過JavaScript與CSS的交互來實現。
  你首先需要檢測的兩個變量是光標相對於整個頁麵的x和y坐標(如程序7-15所示)。因為當前的鼠標坐標隻可能從鼠標事件中取得,你最終需要使用一個普通的鼠標事件來捕獲它們,如MouseOver或MouseDown(這方麵的更多例子見"拖放"小節)。

  程序7-15. 用來在獲取鼠標在整個頁麵中位置的兩個通用函數

//取得鼠標的水平位置
function getX(e) {
    //獲取事件對象
    e = e || window.event;
    //先取非IE的位置,不成功則用IE的位置
    return e.pageX || e.clientX + document.body.scrollLeft;
}
//取得鼠標的垂直位置
function getY(e) {
    //獲取事件對象
    e = e || window.event;
    //先取非IE的位置,不成功則用IE的位置
    return e.pageY || e.clientY + document.body.scrollTop;
}

  需要知道的第二組與鼠標相關的變量是鼠標光標相對於當前交互的元素的位置。可用於取得這些值的兩個函數如程序7-16所示。

程序7-16. 取得鼠標相對於當前元素位置的兩個函數

//取得鼠標相對於事件對象裏e的目標元素(target)的x坐標
function getElementX( e ) {
    //取合適的元素偏移
    return ( e && e.layerX ) || window.event.offsetX;
}
//取得鼠標相對於事件對象裏e的目標元素(target)的x坐標
function getElementY( e ) {
    //取合適的元素偏移
    return ( e && e.layerY ) || window.event.offsetY;
}

  在學習本章的"拖放"這一節裏瀏覽器中元素拖放的實現時,我們將重新回到鼠標交互問題。如需更多的鼠標事件的例子,可參見第六章和附錄B。

  視口

  瀏覽器的視口可認為就是瀏覽器裏被滾動條圍住的區域。視口包含幾個部件:視口窗口,頁麵,滾動條。正確計算它們的位置和尺寸,是在有大段內容的情況下(比如自動滾屏的聊天室)開發漂亮的交互效果的需要。
  頁麵尺寸
  你需要關注的第一組屬性是當前頁麵的寬度和高度。一般來說,大多數的實際的頁麵都被視口所裁切(通過檢查視口尺寸和滾動條位置來判定)。程序7-17所示的兩個函數使用了前麵提到過的scrollWidth和scrollHeight屬性(它們表征了一個部件可能的總的寬度和高度,而不僅僅是當前的可見的那一部分)。

  程序7-17. 判定當前頁麵的寬和高的兩個函數

//返回網頁的高度(如果新的內容被加入,這一值可能會改變)
function pageHeight() {
    return document.body.scrollHeight;
}
//返回網頁的寬度
function pageWidth() {
    return document.body.scrollWidth;
}

  滾動條位置
  接下來,你們將看到怎樣斷定瀏覽器滾動條的位置(或者,在另一個意義上,視口在當前頁麵上的定位情況)。掌握這些數字(使用7-18所示的函數了得),對於超越瀏覽器提供的貧乏的滾動、建立自己更好的動態滾動,是必不可少的。

  程序序7-18. 用來判定視口在文檔上定位於何處和兩個函數

//用來檢測瀏覽器在水平方向滾動了多少的函數
function scrollX() {
    //ie6 strict模式裏的快捷方式
    var de = document.documentElement;
    //如果瀏覽器的pageXOffset可用,則使用之
    return self.pageXOffset ||
    
        //否則,嚐試取得根節點的水平滾動量
        ( de && de.scrollLeft ) ||
    
        //最後,嚐試取得body元素的水平滾動量
        document.body.scrollLeft;
}
//用來檢測瀏覽器在垂直方向滾動了多少的函數
function scrollX() {
    //ie6 strict模式裏的快捷方式
    var de = document.documentElement;
    //如果瀏覽器的pageYOffset可用,則使用之
    return self.pageYOffset ||
    
        //否則,嚐試取得根節點的垂直滾動量
        ( de && de.scrollTop ) ||
    
        //最後,嚐試取得body元素的垂直滾動量
        document.body.scrollTop;
}

  移動滾動條
  擁有了頁麵中滾條的偏移量和頁麵本身的長度信息之後,就可以利用瀏覽器提供的scrollTo方法,調整頁麵上的視口的當前位置。
  scrollTop方法作為window對象(以及任何其它包含可滾動內容元素的元素或者<iframe>)的一個屬性存在,它接收兩個參數,要將視口(或者元素或者<iframe>滾動到的x偏移和y偏移。程序7-19展示了兩個使用scrollTo方法的例子。

  程序7-19. 使用scrollTo方法調整瀏覽器視口位置的例子

//如果你想將視口滾動到瀏覽器的頂部,可以這麼做:
window.scrollTo(0,0);
//如果你想將滾動到特定元素所在位置,可以這麼做:
window.scrollTo( 0, pageY( document.getElementById("body") ) );

  視口尺寸
  有關視口的最後一個可能也是最明顯的方麵:視口本身的尺寸。知道視口的尺寸將能夠洞悉用戶當前可以看到多少內容,不管其屏幕分辨率和瀏覽器窗口是多大。可以使用程序7-20所示的兩個函數來得到那些值。

  程序7-20. 判定瀏覽器視口高度和寬度的兩個函數

//取得視口高度
function windowHeight() {
    //ie6 strict模式裏的快捷方式
    var de = document.documentElement;
    //如果瀏覽器的innerHeight可用,則使用它
    return self.innerHeight ||
        //否則,嚐試獲得根節點的高度
        ( de && de.clientHeight ) ||
        //最後,嚐試獲得body元素的高度
        document.body.clientHeight;
}
//取得視口高度
function windowWidth() {
    //ie6 strict模式裏的快捷方式
    var de = document.documentElement;
    //如果瀏覽器的innerWidth可用,則使用它
    return self.innerWidth ||
        //否則,嚐試獲得根節點的寬度
        ( de && de.clientWidth ) ||
        //最後,嚐試獲得body元素的寬度
        document.body.clientWidth;
}

  操作視口的重要性不容忽視。隨便查看一個現代web應用程序,如Gmail或Campfire,都能找到操作視口以提供引人注目的結果的實例(Gmail提供了上下文相關的覆蓋圖,而Campfire提供了自動滾動的聊天室)。在第十一章中我將討論在高交互性的web應用程序中視口可用來提供更好的體驗的不同的方式。

[ 本帖最後由 mozart0 於 2007-6-20 08:55 編輯 ]

頂部
one by one
mozart0

匪徒田老大



帖子 2326
體力 6628
威望 177
注冊 2003-6-18

發表於 2007-5-14 13:14  資料  短消息  加為好友  QQ
拖放

  瀏覽器上可實現的最流行的交互之一,是將一個元素在頁麵裏拖動。使用你所學的技能(判定元素位置的能力,怎樣調整位置,各種定位方式的不同),你現在已可以完全理解拖放係統是怎樣工作的。
  為了探索這一技術,我選擇參照Aaron Boodman創建的DOM-Drag庫(https://boring.youngpup.net/2001/domdrag)。他的庫裏提供了許多便捷的功能,包含以下幾種:
  拖動手柄: 你可以擁有一個真正被移動的父元素和另一個被拖動的子元素。這對於創建具有窗口外觀的界麵是很好的。
  回調函數: 你可以監視指定事件,如用戶何時開始拖動元素、正在拖動元素、停止拖動元素,並得到元素的當前位置信息。
  最小/最大拖動區域: 你可以限定一個元素不能拖動到特定的區域之外(如屏幕之外)。這對於建造滾動條是很完美的。
  自定義坐標係統: 你可以選擇操作一套x/y坐標係統映射,如果對使用css坐標係統感覺不爽的話。
  自定義x和y坐標係統轉換: 你可以使你拖動的元素以非傳統的方式移動(如上下搖動或波浪形運動)。
  DOM-Drag係統的使用是相當簡單的。程序7-12展示了一些使用DOM-Drag的例子。

  程序7-21. 使用DOM-Drag模擬瀏覽器內的可拖動窗口

<html>
<head>
    <title>DOM-Drag – Draggable Window Demo</title>
    <script src="domdrag.js" type="text/javascript"></script>
    <script type="text/javascript">
    window.onload = function(){
        //初始化DOM-Drag函數,使id為"window"的元素可拖動
        Drag.init( document.getElementById("window") );
    };
    </script>
    <style>
    #window {
        border: 1px solid #DDD;
        border-top: 15px solid #DDD;
        width: 250px;
        height: 250px;
        position:relative;//譯者加的,原文漏了
    }
    </style>
</head>
<body>
    <h1>Draggable Window Demo</h1>
    <div >I am a draggable window, feel free to move me around!</div>
</body>
</html>

  7-22是DOM-Drag的一個帶有完整文檔的版本。代碼作為單個的全局對象存在,該對象的方法可在頁麵元素上調用,以初始化拖放過程。
  程序7-22. 帶有完整文檔的DOM-Drag庫

var Drag = {
    // 被拖動的當前元素
    obj: null,
    //拖動元素的初始化函數
    // o = 做為拖動手柄的元素
    // oRoot = 被拖動的元素,如未指明,拖動手柄本身將為被拖動元素
    // minX, maxX, minY, maxY = 允許的元素最小和最大坐標
    // bSwapHorzRef = 切換到水平坐標係統
    // bSwapVertRef = 切換到垂直坐標係統
    // fxMapper, fyMapper = 另行映射x和y坐標的函數
    init: function(o, oRoot, minX, maxX, minY,
    maxY, bSwapHorzRef, bSwapVertRef, fXMapper, fYMapper) {
        //監視拖動事件的開始
        o.onmousedown = Drag.start;
    
        //確定使用哪個坐標係統
        o.hmode = bSwapHorzRef ? false : true ;
        o.vmode = bSwapVertRef ? false : true ;
        //確定哪個元素做做為句柄
        o.root = oRoot && oRoot != null ? oRoot : o ;
        //初始化指定的坐標係統
        if (o.hmode && isNaN(parseInt(o.root.style.left )))
            o.root.style.left = "0px";
        if (o.vmode && isNaN(parseInt(o.root.style.top )))
            o.root.style.top = "0px";
        if (!o.hmode && isNaN(parseInt(o.root.style.right )))
            o.root.style.right = "0px";
        if (!o.vmode && isNaN(parseInt(o.root.style.bottom)))
            o.root.style.bottom = "0px";
        //檢查用戶是否提供的最小/最大坐標限定
        o.minX = typeof minX != 'undefined' ? minX : null;
        o.minY = typeof minY != 'undefined' ? minY : null;
        o.maxX = typeof maxX != 'undefined' ? maxX : null;
        o.maxY = typeof maxY != 'undefined' ? maxY : null;
        //檢查指定的任何坐標映射函數
        o.xMapper = fXMapper ? fXMapper : null;
        o.yMapper = fYMapper ? fYMapper : null;
        //為所有的用戶定義的函數添加外殼(shells)
        o.root.onDragStart = new Function();
        o.root.onDragEnd = new Function();
        o.root.onDrag = new Function();
    },
    start: function(e) {
        //找到正被拖動的元素
        var o = Drag.obj = this;
        //規範化事件對象
        e = Drag.fixE(e);
        //取得當前x和y坐標
        var y = parseInt(o.vmode ? o.root.style.top : o.root.style.bottom);
        var x = parseInt(o.hmode ? o.root.style.left : o.root.style.right );
        //以x和y坐標調用用戶的函數
        o.root.onDragStart(x, y);
        //記錄起始鼠標位置
        o.lastMouseX = e.clientX;
        o.lastMouseY = e.clientY;
        //如果我們正使用CSS坐標係統
        if (o.hmode) {
            //設定可用的最小和最大坐標
            if (o.minX != null) o.minMouseX = e.clientX - x + o.minX;
            if (o.maxX != null) o.maxMouseX = o.minMouseX + o.maxX - o.minX;
        //否則,我們正使用傳統的數學坐標係統
        } else {
            if (o.minX != null) o.maxMouseX = -o.minX + e.clientX + x;
            if (o.maxX != null) o.minMouseX = -o.maxX + e.clientX + x;
        }
        //監聽拖動和拖動結束事件
        document.onmousemove = Drag.drag;
        document.onmouseup = Drag.end;
        return false;
    },
    //在拖動事件中監視所有的鼠標運行的函數
    drag: function(e) {
        //規範化事件對象
        e = Drag.fixE(e);
        //得到正被拖動的對象的引用
        var o = Drag.obj;
        //取得鼠標在窗口中的位置
        var ey = e.clientY;
        var ex = e.clientX;
        //得到當前坐標
        var y = parseInt(o.vmode ? o.root.style.top : o.root.style.bottom);
        var x = parseInt(o.hmode ? o.root.style.left : o.root.style.right );
        var nx, ny;
        //如果設定了最小x坐標,確保不會超過它
        if (o.minX != null) ex = o.hmode ?
            Math.max(ex, o.minMouseX) : Math.min(ex, o.maxMouseX);
        //如果設定了最大x坐標,確保不會超過它
        if (o.maxX != null) ex = o.hmode ?
            Math.min(ex, o.maxMouseX) : Math.max(ex, o.minMouseX);
        //如果設定了最小y坐標,確保不會超過它
        if (o.minY != null) ey = o.vmode ?
            Math.max(ey, o.minMouseY) : Math.min(ey, o.maxMouseY);
        //如果設定了最小y坐標,確保不會超過它
        if (o.maxY != null) ey = o.vmode ?
            Math.min(ey, o.maxMouseY) : Math.max(ey, o.minMouseY);
        //計算轉換後的新的x和y坐標
        nx = x + ((ex - o.lastMouseX) * (o.hmode ? 1 : -1));
        ny = y + ((ey - o.lastMouseY) * (o.vmode ? 1 : -1));
        //並再次使用x和y映射函數(如果提供了)轉換它們
        if (o.xMapper) nx = o.xMapper(y)
        else if (o.yMapper) ny = o.yMapper(x)
        //為元素設置新的x和y坐標
        Drag.obj.root.style[o.hmode ? "left" : "right"] = nx + "px";
        Drag.obj.root.style[o.vmode ? "top" : "bottom"] = ny + "px";
        //並記錄鼠標的最後位置
        Drag.obj.lastMouseX = ex;
        Drag.obj.lastMouseY = ey;
        //使用當前的x和y坐標調用用戶的onDrag函數
        Drag.obj.root.onDrag(nx, ny);
        return false;
    },
    //處理拖放結束的函數
    end: function() {
        //不在監視鼠標事件(因為拖放已經結束)
        document.onmousemove = null;
        document.onmouseup = null;
        //在拖放事件的最後,用元素的x和y坐標調用我們的特別的onDragEnd函數
        Drag.obj.root.onDragEnd(
            parseInt(Drag.obj.root.style[Drag.obj.hmode ? "left" : "right"]),
            parseInt(Drag.obj.root.style[Drag.obj.vmode ? "top" : "bottom"]));
        //不再監視拖動的對象
        Drag.obj = null;
    },
    //規範化事件對象的函數
    fixE: function(e) {
        //如果e不存在,則是IE瀏覽器,於是使用IE的event對象
        if (typeof e == 'undefined') e = window.event;
        //如果layer屬性沒有設置,則從等效的屬性中取得
        if (typeof e.layerX == 'undefined') e.layerX = e.offsetX;
        if (typeof e.layerY == 'undefined') e.layerY = e.offsetY;
        return e;
    }
};

  平心而論,DOM-Drag算是數以百計的JavaScript拖放庫中比較簡單的一個。但是我個人特別喜歡它,因其整潔的麵向對象語法和相對的簡單性。下一節中我將論述Scriptaculous庫,它擁有一個出色而強大的拖放的實現,我強烈推薦你們去研究一下。

[ 本帖最後由 mozart0 於 2007-6-20 08:55 編輯 ]

頂部
one by one
mozart0

匪徒田老大



帖子 2326
體力 6628
威望 177
注冊 2003-6-18

發表於 2007-5-14 13:14  資料  短消息  加為好友  QQ


  正如JavaScript裏多數枯燥的任務一樣,如果你想要開發出一個效果或者交互,極有可能它已經被創造出來了。下麵將快速地瀏覽三種提供了不同的DHTML交互的庫,你將知道作為開發者,有些什麼拿來就可以用。

  moo.fx和jQuery

  有兩種擅長於簡單效果的輕量級的庫:moo.fx和jQuery。這兩個庫都提供了一套基本的效果,可以用來組合以創建有效而簡單的動畫。關於它們的更多信息可以在其各自的相關網站上找到。程序7-23展示了這兩個庫的一些基本的例子。

  程序7-23. 使用moo.fx和jQuery的動畫的基本例子

//一個簡單的動畫:元素的隱藏部分被展開,完成以後,再次收縮
//這一動畫的moo.fx實現
new fx.Height( "side", {
    duration: 1000,
    onComplete: function() {
        new fx.Height( "side", { duration: 1000 } ).hide();
    }
}).show();
// jQuery的實現
$("#side").slideDown( 1000, function(){
    $(this).slideUp( 1000 );
});
//另一個簡單的動畫:元素的高度、寬度和透明度全部同步收縮或降低,產生一個很酷的隱藏效果
//此動畫的moo.fx實現
new fx.Combo( "body", {
    height: true,
    width: true,
    opacity: true
}).hide();
//此動畫的jQuery實現
$("#body").hide( "fast" );

  正如你從例子中可能已看到的,moo.fx和jQuery使得執行一些小巧的動畫變成非常容易。兩個項目都在其網站上提供了大量的應用其代碼的例子,這是了解簡單的JavaScript動畫怎樣工作的很好的方式。
  moo.fx的主頁:https://moofx.mad4milk.net/
  mootoolkit文檔和示例:https://moofx.mad4milk.net/
  jQuery的主頁:https://jquery.com/
  jQuery效果和文檔和示例:https://jquery.com/docs/fx/

  Scriptaculous

  如果說有一個庫在所有的DHTML庫中可以王者稱之的話,那非Scriptaculous莫屬。基於流行的Prototype庫,Scriptaculous提供了海量的各式效果,從動畫效果到

最後更新:2017-04-02 00:06:24

  上一篇:go Pro JavaScript Techniques第三章: 創建可重用的代碼
  下一篇:go 網絡廣告的計費方式,網站賺錢