天天看點

JavaScript進階程式設計II

        在前面的文章中,我們介紹了兩類JavaScript小工具及其源碼:浮動文本和彈出菜單。本文中,我們将繼續介紹另外幾個有用的JavaScript小工具,并着重說明其工作原理,是以你可以簡單修改後應用到自己的程式中。本文中的JavaScript代碼應該不用做任何修改就可以在目前所有主流浏覽器上運作。是以,不用再費周折……

        使用div标簽的圖檔切換(Image Toggling with the div Tag)

        很多情況下,你可能想要把網頁上的一類東西放在一起,例如圖檔,但是它們又會占據太多的空間。為什麼不隻放置一張圖檔,而讓使用者使用一個開關在圖檔之間切換呢?如下:

Image 1Image 2Image 3

        其實,這非常簡單。注意,浏覽器在每次切換時并沒有去請求伺服器,切換是立即完成。竅門呢?把它們全部放到HTML中,但是每次隻顯示一個。這個效果可以使用div标簽及其樣式輕松完成。使用這個技術可以實作很多令人印象深刻的效果,接下來的例子将會看到。但是首先,我們還是了解一下這個例子是如何工作的。使用到的JavaScript函數隻有一個:        

JavaScript進階程式設計II

function ShowImage(page, tag)

JavaScript進階程式設計II
JavaScript進階程式設計II

...{

JavaScript進階程式設計II

    var i = 1;

JavaScript進階程式設計II

    var el;

JavaScript進階程式設計II
JavaScript進階程式設計II

    while (el = document.getElementById(tag + i)) ...{

JavaScript進階程式設計II

        if (i == page)

JavaScript進階程式設計II

            el.style.display = 'block';

JavaScript進階程式設計II

        else

JavaScript進階程式設計II

            el.style.display = 'none';

JavaScript進階程式設計II

        i++;

JavaScript進階程式設計II

    }

JavaScript進階程式設計II

}

          實際的圖檔被放在HTML中它們應該出現的位置上,每一個都有一個div标簽包括,如下:

JavaScript進階程式設計II

<table>

JavaScript進階程式設計II

    <tr valign="top">

JavaScript進階程式設計II

        <td>

JavaScript進階程式設計II

            <div style="display:block" id="image1">

JavaScript進階程式設計II

                <img src="/onlamp/2007/08/23/graphics/pic1.jpg" />

JavaScript進階程式設計II

            </div>

JavaScript進階程式設計II

            <div style="display:none" id="image2">

JavaScript進階程式設計II

                <img src="/onlamp/2007/08/23/graphics/pic2.jpg" />

JavaScript進階程式設計II
JavaScript進階程式設計II

            <div style="display:none" id="image3">

JavaScript進階程式設計II

                <img src="/onlamp/2007/08/23/graphics/pic3.jpg" />

JavaScript進階程式設計II
JavaScript進階程式設計II

        </td>

JavaScript進階程式設計II

        <td width="100%" align="right">

JavaScript進階程式設計II

            <select onchange="ShowImage(parseInt(this.value), 'image');">

JavaScript進階程式設計II

                <option selected="selected" value="1">Image 1</option>

JavaScript進階程式設計II

                <option value="2">Image 2</option>

JavaScript進階程式設計II

                <option value="3">Image 3</option>

JavaScript進階程式設計II

            </select>

JavaScript進階程式設計II
JavaScript進階程式設計II

    </tr>

JavaScript進階程式設計II

</table>

         這個table的結構隻是為了布局,是以根據本文讨論的目的可以忽略。重要的是,表格的第一個單元格中的三個div标簽。注意,第一個div标簽的display設定為了block,而其他幾個設定為了none。任何display被設為none的内容被隐藏了,也就不會在浏覽器視窗中繪制,盡管已經從伺服器上取得,并且放到了頁面上。是以,剛開始我們隻看到pic1.jp,而沒有看到另外兩張。

        然後,我們在下拉框的onchange事件發生時調用上面JavaScript函數。當使用者在下拉框選擇新的項目時就會觸發該事件。我們傳遞兩個參數:下拉框本身的引用和包含了所有圖檔的div标簽id基礎部分(注意image1、image2和image3都是以image開頭)。

         函數先獲得表示哪一個圖檔需要顯示的選擇值。parseInt用來保證儲存的是數字而不是字元串。接下來獲得第一個div标簽的句柄,本例中是id為image1的div。如果這個圖檔需要顯示,就将它的display樣式設定為block,其他的設定為none。然後,接着處理下一個标簽(image2),等等,直到沒有了需要處理的标簽,這是退出函數。

        是以,隻要下拉框中的新選項被選擇,其相應的div區域就會顯示,而其他的被隐藏。它們在網頁上共享同一塊區域,因為在HTML中它們一個個緊挨着的。然而,這當然不是一個限制,如果需要我們可以讓它們穿過不同的區域,也可以根據不同的選擇出現在網頁上不同的位置。相似地,我們也沒有限制隻能是圖檔;隻要是可以放在div标簽中的任何東西都可以使用滑鼠點選顯示或隐藏。這個功能使你可以在頁面放置更多的資訊,而不需要使用者拖動滾動條。

        tab:使用div的更多樂趣(Tabs: More Fun with div)

        接下來我們看使用div标簽的創造性作用的另外一個例子。有時候,需要在頁面包含幾個tab頁。點選一個tab頁面,就會顯示其包含的資訊,隐藏其他的,很像目前一系列的tab類型的web浏覽器(譯者注:Firefox和IE7都是這種形式)。但是,通常情況下,點選HTML的tab會引起頁面的重載,這肯定會打斷界面的連貫性。有沒有資訊可以立即呈現的方法呢?的确要感謝我們在上個例子中學到的小技巧,它可以完成。試一下吧:

Summary

Details

Known Issues

Introducing the new, improved multi-widget. It slices, it dices, it even does your taxes! Order yours today! Call now: 555-WIDG

The multi-widget is a sophisticated piece of complex machinery designed by the country's leading nuclear physicists. Order yours today and you will quickly learn how easy it is to do just about anything in no time, thanks to our patented EZ-Widge technology.

Motor: 5HP

Dimensions: 8" x 5" x 2"

Weight: 212 g

Radioactivity: negligible

Do not use multi-widget near open flames

Do not run while holding multi-widget

Do not taunt multi-widget

Multi-widget may, under certain as yet undetermined circumstances, spontaneously explode. We hereby disclaim any libaility for personal injury caused as a result of multi-widget; for your safety, we recommend wearing body armor while handling multi-widget.

         沒有什麼值得驚奇的,這個例子使用了和上一個完全一樣的JavaScript函數,但是實作了一個完全不同的效果。其餘的效果有幾條簡單CSS規則實作。我們先看一下例子中的HTML代碼:

JavaScript進階程式設計II

<div style="display:block" id="tab1">

JavaScript進階程式設計II

    <ul class="tab">

JavaScript進階程式設計II

        <li class="tab_selected" onclick="ShowImage(1, 'tab');">

JavaScript進階程式設計II

            Summary

JavaScript進階程式設計II

        </li>

JavaScript進階程式設計II

        <li onclick="ShowImage(2, 'tab');">

JavaScript進階程式設計II

            Details

JavaScript進階程式設計II
JavaScript進階程式設計II

        <li onclick="ShowImage(3, 'tab');">

JavaScript進階程式設計II

            Known Issues

JavaScript進階程式設計II
JavaScript進階程式設計II

    </ul>

JavaScript進階程式設計II

    <p>

JavaScript進階程式設計II

        Introducing the new, improved multi-widget.  It slices, it dices, it even does

JavaScript進階程式設計II

        your taxes!  Order yours today!  Call now: 555-WIDG

JavaScript進階程式設計II

    </p>

JavaScript進階程式設計II

</div>

JavaScript進階程式設計II
JavaScript進階程式設計II

<div style="display:none" id="tab2">

JavaScript進階程式設計II
JavaScript進階程式設計II

        <li onclick="ShowImage(1, 'tab');">

JavaScript進階程式設計II
JavaScript進階程式設計II
JavaScript進階程式設計II

        <li class="tab_selected" onclick="ShowImage(2, 'tab');">

JavaScript進階程式設計II
JavaScript進階程式設計II
JavaScript進階程式設計II
JavaScript進階程式設計II
JavaScript進階程式設計II
JavaScript進階程式設計II
JavaScript進階程式設計II
JavaScript進階程式設計II

        The multi-widget is a sophisticated piece of complex machinery designed by the

JavaScript進階程式設計II

        country's leading nuclear physicists.  Order yours today and you will quickly

JavaScript進階程式設計II

        learn how easy it is to do just about anything in no time, thanks to our patented

JavaScript進階程式設計II

        EZ-Widge technology.

JavaScript進階程式設計II
JavaScript進階程式設計II
JavaScript進階程式設計II

        Motor: 5HP<br />

JavaScript進階程式設計II

        Dimensions: 8" x 5" x 2"<br />

JavaScript進階程式設計II

        Weight: 212 g<br />

JavaScript進階程式設計II

        Radioactivity: negligible

JavaScript進階程式設計II
JavaScript進階程式設計II
JavaScript進階程式設計II
JavaScript進階程式設計II

<div style="display:none" id="tab3">

JavaScript進階程式設計II
JavaScript進階程式設計II
JavaScript進階程式設計II
JavaScript進階程式設計II
JavaScript進階程式設計II
JavaScript進階程式設計II
JavaScript進階程式設計II
JavaScript進階程式設計II

        <li class="tab_selected" onclick="ShowImage(3, 'tab');">

JavaScript進階程式設計II
JavaScript進階程式設計II
JavaScript進階程式設計II
JavaScript進階程式設計II
JavaScript進階程式設計II

    <ul>

JavaScript進階程式設計II

        <li>Do not use multi-widget near open flames</li>

JavaScript進階程式設計II

        <li>Do not run while holding multi-widget</li>

JavaScript進階程式設計II

        <li>Do not taunt multi-widget</li>

JavaScript進階程式設計II

        <li>

JavaScript進階程式設計II

            Multi-widget may, under certain as yet undetermined circumstances,

JavaScript進階程式設計II

            spontaneously explode.  We hereby disclaim any libaility for personal injury

JavaScript進階程式設計II

            caused as a result of multi-widget; for your safety, we recommend wearing

JavaScript進階程式設計II

            body armor while handling multi-widget.

JavaScript進階程式設計II
JavaScript進階程式設計II
JavaScript進階程式設計II

        注意,這裡有三個div區域(每一個是一個tab),就像上一個例子中每個圖檔有一個div。再次說明,第一個div被賦予display:block,而其他是display:none,是以剛開始隻有第一個div可見。這些區域每一個都是先繪制三個tab,選中的tab和其他的顔色不同。是以,我們實際上在每一個tab上都重新繪制了三個tab。tab的内容可以是任何HTML。注意,内容隻出現一次,隻不過tab的HTML重複了多次,是以“浪費”的空間是最小的。

        每個tab在觸發onclick事件時就會調用JavaScript函數ShowImage。就像我們在第一個例子中看到的,這個函數隐藏了除作為參數傳遞給ShowImage的div之外的其他div區域。是以,我們在這裡使用顯示點選的tab,隐藏其他的。CSS或者樣式用來實際繪制tab。我們定義了兩個類:tab和tab_selected。前者應用于整個tab欄,而後者隻用于被選擇的tab。CSS的代碼如下:       

JavaScript進階程式設計II
JavaScript進階程式設計II

ul.tab {...}{

JavaScript進階程式設計II

    margin: 0;

JavaScript進階程式設計II

    padding: 3px 0;

JavaScript進階程式設計II

    border-bottom: 1px solid #778;

JavaScript進階程式設計II

    font-weight: bold;

JavaScript進階程式設計II
JavaScript進階程式設計II
JavaScript進階程式設計II
JavaScript進階程式設計II

ul.tab li {...}{

JavaScript進階程式設計II

    display: inline;

JavaScript進階程式設計II

    padding: 3px 0.5em;

JavaScript進階程式設計II

    margin-left: 3px;

JavaScript進階程式設計II

    border-top: 1px solid #778;

JavaScript進階程式設計II

    border-left: 1px solid #778;

JavaScript進階程式設計II

    border-right: 1px solid #778;

JavaScript進階程式設計II

    border-bottom: none;

JavaScript進階程式設計II

    background: top repeat-x #89aac7;

JavaScript進階程式設計II

    white-space: nowrap;

JavaScript進階程式設計II

    color: white;

JavaScript進階程式設計II

    cursor:pointer;

JavaScript進階程式設計II
JavaScript進階程式設計II
JavaScript進階程式設計II
JavaScript進階程式設計II

ul.tab li.tab_selected {...}{

JavaScript進階程式設計II

    background: #fff;

JavaScript進階程式設計II

    border-bottom: 1px solid #fff;

JavaScript進階程式設計II

    color: black;

JavaScript進階程式設計II

        第一部分用于ul标簽,也就是整個tab欄。它設定margin和padding屬性,指定所有tab靠左排列,并在tab欄的下面繪制一條邊線。要讓tab排成合适的隊列,padding屬性是必須設定的。另外,我們把tab欄中的文本加粗。

        接下來的部分用在tab欄中的所有li标簽上。display:inline可能是最重要的,它讓清單橫向排列代替縱向。還是margin和padding屬性讓tab排成一行,并且在相鄰tab之間留下一定空隙。border屬性設定tab的頂部和兩邊的邊線(底部的邊線來自ul标簽)。最後,設定背景和前景色,確定文字不會換行。

        最後一部分之應用于目前選中的tab,覆寫了第二部分中的一些屬性設定。改變了tab的背景和前景色,使其突出,同時使用白色的底線掩蓋了ul标簽的黑色底線。這樣就有了選中的tab在其他tab之前的感覺。

        在本例中,tab的所有被加載後儲存在網頁上,是以點選一個tab時幾乎是立即呈現其内容,不會引起頁面的任何重載。使用一個十分簡單的JavaScript函數和一小段CSS,我們就得到了真正令人印象深刻的效果。

        div得更多技巧(And Even More div  Tricks)

        和上一個例子中我們學到有用的應用程式的技巧一樣,嘗試下面的例子,可以用來作為文本或清單的總結性區域,允許使用者隻展開和檢視他/她感興趣的内容:           

Choice of four widget colors

blue

green

red

brown

         源代碼如下:

JavaScript進階程式設計II

<div style="display:block;" id="colors1">

JavaScript進階程式設計II

    <table style="background:#eeeebb">

JavaScript進階程式設計II

        <tr>

JavaScript進階程式設計II

            <td>

JavaScript進階程式設計II

                <img src="/onlamp/2007/08/23/graphics/expand.jpg" style="cursor:pointer;"

JavaScript進階程式設計II

                alt="Click to Expand" title="Click to Expand" onclick="ShowImage(2, 'colors');" />

JavaScript進階程式設計II

            </td>

JavaScript進階程式設計II
JavaScript進階程式設計II

                Choice of four widget colors

JavaScript進階程式設計II
JavaScript進階程式設計II

        </tr>

JavaScript進階程式設計II

    </table>

JavaScript進階程式設計II
JavaScript進階程式設計II

<div style="display:none;" id="colors2">

JavaScript進階程式設計II
JavaScript進階程式設計II

        <tr valign="top">

JavaScript進階程式設計II
JavaScript進階程式設計II

                <img src="/onlamp/2007/08/23/graphics/collapse.jpg" style="cursor:pointer;"

JavaScript進階程式設計II

                alt="Click to Collapse" title="Click to Collapse" onclick="ShowImage(1, 'colors');" />

JavaScript進階程式設計II
JavaScript進階程式設計II
JavaScript進階程式設計II

                <ul>

JavaScript進階程式設計II

                    <li>blue</li>

JavaScript進階程式設計II

                    <li>green</li>

JavaScript進階程式設計II

                    <li>red</li>

JavaScript進階程式設計II

                    <li>brown</li>

JavaScript進階程式設計II

                </ul>

JavaScript進階程式設計II
JavaScript進階程式設計II
JavaScript進階程式設計II
JavaScript進階程式設計II

       如今,這個效果是如何完成的應該相當清楚了。再說一次,這裡有兩個div塊,一個是折疊樣式的文本和展開按鈕,另一個是展開樣式的文本和折疊按鈕。最初,我們隻看到折疊樣式(display:block),接着我們使用圖檔的onclick回調在兩個div之間切換。兩個div的id分别為colors1和colors2,這樣就便于使用我們前面編寫的JavaScript函數ShowImage。

       拖拽和切換(Drag and Drop and Swap)

       現在,我已經過多的分析和讨論了div标簽,下面我們就來看一些不同的東西。在這個例子中,我們展示一個使用滑鼠拖拽文本(或圖檔)的方法。這也可以用來實作JavaScript遊戲或者更加重要的目的,例如,允許你更換頁面中圖檔的順序。在下面的例子中,嘗試拖拽三個名字來更換它們的位置。注意,你可以沒有任何問題的交換John和Jane,但是卻不能交換Bill和另外兩個的位置,因為他總是搗亂。

John

Jane

Bill

(譯者注:由于blog限制,不能在本頁面中示範其效果,可以通過頂部連結進入原文檢視其運作結果)

        這個例子比至今為止的其他例子包含更多的代碼,但是它仍然是相當易于了解的。和其他例子不同,它使用了全局滑鼠事件。特别指出,它依賴于三個回調函數:按下滑鼠、移動滑鼠和釋放滑鼠。使用這些類别的全局事件缺點是,如果一次觸發多個事件,就會變得非常危險。是以,你應該最小化這些事件的同時使用,在每個頁面最多使用一個或者兩個。對于這樣一個特别例子,全局事件是非常必要的。下面我們每一次隻看一部分代碼:

JavaScript進階程式設計II

// Set the callbacks

JavaScript進階程式設計II

document.onmousedown = mousedown;

JavaScript進階程式設計II

document.onmousemove = movemouse;

JavaScript進階程式設計II

document.onmouseup   = mouseup;

JavaScript進階程式設計II
JavaScript進階程式設計II

var lastobj;  // Last draggable object we hovered over

JavaScript進階程式設計II

var isdrag;   // True if dragging an object

        此處,我們初始化三個回調函數。mousedown在使用者點選滑鼠時調用,movemouse在移動滑鼠時調用,而mouseup在釋放滑鼠左鍵時被調用。我們還需要兩個全局變量,第一個跟蹤我們最近懸停的對象,第二個是一個标志,表示我們目前是否正在拖動一個對象。        

JavaScript進階程式設計II

// This prevents browsers from highlighting the draggable text

JavaScript進階程式設計II

// when you click on it.  The table containing all the draggable

JavaScript進階程式設計II

// text has id drag_drop.

JavaScript進階程式設計II
JavaScript進階程式設計II

window.onload = function()

JavaScript進階程式設計II
JavaScript進階程式設計II
JavaScript進階程式設計II

    var e = document.getElementById('drag_drop');

JavaScript進階程式設計II
JavaScript進階程式設計II

    if (e) ...{

JavaScript進階程式設計II

        if (moz)

JavaScript進階程式設計II
JavaScript進階程式設計II

            e.onmousedown = function () ...{ return false; } // mozilla

JavaScript進階程式設計II
JavaScript進階程式設計II
JavaScript進階程式設計II

            e.onselectstart = function () ...{ return false; } // ie

JavaScript進階程式設計II
JavaScript進階程式設計II

        這個短小的函數在頁面一裝載時就執行,它確定點選可拖拽對象時,文本不會高亮,就好像點選正常的文本一樣。實作原理是使用一個空函數重寫了負責高亮顯示文本的函數。       

JavaScript進階程式設計II

// Checks to see if a swap is allowed between two objects based on their ids.

JavaScript進階程式設計II

// Change this as you see fit to permit or forbid swapping each possible pair

JavaScript進階程式設計II

// of draggable items.

JavaScript進階程式設計II

function allowswap(a,b)

JavaScript進階程式設計II
JavaScript進階程式設計II
JavaScript進階程式設計II

    if (a.id == "dragdropa" && b.id == "dragdropb" || a.id == "dragdropb" && b.id == "dragdropa")

JavaScript進階程式設計II

        return true;

JavaScript進階程式設計II

    return false;

JavaScript進階程式設計II
JavaScript進階程式設計II
JavaScript進階程式設計II

// Returns true if an object is draggable - change this to suit your needs.

JavaScript進階程式設計II

function isdraggable(obj)

JavaScript進階程式設計II
JavaScript進階程式設計II
JavaScript進階程式設計II

    if (obj.id.substr(0,8) == "dragdrop")

JavaScript進階程式設計II
JavaScript進階程式設計II
JavaScript進階程式設計II

         這裡是兩個我們需要的工具函數;輸入兩個對象,如果它們可以交換位置,allowswap則傳回true,否則傳回false。很明顯,在這個位置使用一些頗具奧妙的邏輯,你就可以完成一些有趣的事情。如果輸入的對象是可以拖拽的,isdraggable傳回true。根據本例的目的,我們隻判斷id以dragdrop開頭的對象,當然,你可以根據需要改變。可拖拽性也可以使用其他方式表示,例如一個特别的類(class),但是這裡基于我們例子的目的。        

JavaScript進階程式設計II

// Callback when mouse button is pressed.  This checks if an item is draggable, and

JavaScript進階程式設計II

// if so initiates the process.

JavaScript進階程式設計II

function mousedown(e) 

JavaScript進階程式設計II
JavaScript進階程式設計II
JavaScript進階程式設計II

    var obj = moz ? e.target : event.srcElement;

JavaScript進階程式設計II

    // Trace up DOM tree to see if item clicked on is draggable.  This allows

JavaScript進階程式設計II

    // for the fact that you may click, for example, on a TD while the enclosing

JavaScript進階程式設計II

    // TR is the draggable object.

JavaScript進階程式設計II
JavaScript進階程式設計II

    while (obj.tagName != "HTML" && obj.tagName != "BODY" && !isdraggable(obj)) ...{

JavaScript進階程式設計II

        obj = moz ? obj.parentNode : obj.parentElement;

JavaScript進階程式設計II
JavaScript進階程式設計II
JavaScript進階程式設計II

    if (isdraggable(obj)) ...{

JavaScript進階程式設計II

        // If draggable, set a global flag to track this, and save a pointer

JavaScript進階程式設計II

        // to the object in a global variable as well (dragobj).

JavaScript進階程式設計II

        isdrag = true;

JavaScript進階程式設計II

        dragobj = obj;

JavaScript進階程式設計II
JavaScript進階程式設計II

        // origx, origy is original starting location of dragged object

JavaScript進階程式設計II

        origx = dragobj.style.left;

JavaScript進階程式設計II

        origy = dragobj.style.top;

JavaScript進階程式設計II
JavaScript進階程式設計II

        // x,y is absolute co-ordinates within the window

JavaScript進階程式設計II

        x = moz ? e.clientX : event.clientX;

JavaScript進階程式設計II

        y = moz ? e.clientY : event.clientY;

JavaScript進階程式設計II
JavaScript進階程式設計II

        // While offsetX, offSetY depend on where exactly you clicked on the object.

JavaScript進階程式設計II

        // Thus if you click in the middle of the object, it will be 'attached' to

JavaScript進階程式設計II

        // the mouse at that point, and not the upper left corner, for example.

JavaScript進階程式設計II

        offsetX = moz ? e.layerX + 2: event.x + 2;

JavaScript進階程式設計II

        offsetY = moz ? e.layerY + 2: event.y + 2;

JavaScript進階程式設計II
JavaScript進階程式設計II

         滑鼠按下時調用mousedown,這是這段代碼裡的第一個主要的部分。那麼,當點選某個對象時,我們要檢查它是否可以拖拽。如果不可以,則檢查其父對象是否可以拖拽等等。這是因為當我們點選某個對象時,浏覽器往往傳回DOM樹中最底層、最深層的對象。那麼例如,有一個包含了p标簽并可以拖拽的span标簽,點選p标簽中的文字,你将會得到p标簽的句柄,但是它并不可拖拽。然而檢查其父對象,我們将會發現作為一個可拖拽對象的子對象,它實際上是可以拖拽 的。

        假設我們點選了一個可拖拽對象,我們要将全局标志設為true,把對象儲存在dragobj中。我們還要儲存幾個坐标:dragobj的原始位置、點選時的滑鼠相對位置和點選的絕對位置。       

JavaScript進階程式設計II

// Callback when mouse is moved.  It will change the cursor when you move over an object

JavaScript進階程式設計II

// you can - or cannot - swap with.

JavaScript進階程式設計II
JavaScript進階程式設計II

function movemouse(e)

JavaScript進階程式設計II
JavaScript進階程式設計II
JavaScript進階程式設計II

    // Check if we are dragging an object

JavaScript進階程式設計II
JavaScript進階程式設計II

    if (isdrag) ...{

JavaScript進階程式設計II

        // If so, set the dragged object's position relative to how much the mouse has moved

JavaScript進階程式設計II

        // since first clicked.

JavaScript進階程式設計II

        dragobj.style.left = moz ? origx + e.clientX - x + offsetX + 'px' : origx + event.clientX - x + offsetX;

JavaScript進階程式設計II

        dragobj.style.top  = moz ? origy + e.clientY - y + offsetY + 'px' : origy + event.clientY - y + offsetY;

JavaScript進階程式設計II

        var obj = moz ? e.target : event.srcElement;

JavaScript進階程式設計II
JavaScript進階程式設計II

        // If we are over an element that we cannot swap with, change its cursor style

JavaScript進階程式設計II

        // to show that a swap is forbidden

JavaScript進階程式設計II
JavaScript進階程式設計II

        if (obj != dragobj && isdraggable(obj) && !allowswap(dragobj,obj)) ...{

JavaScript進階程式設計II

            obj.style.cursor = 'wait';

JavaScript進階程式設計II

            // save in a handle to the object in a global so we can reset the cursor later

JavaScript進階程式設計II

            lastobj = obj;

JavaScript進階程式設計II

        }

JavaScript進階程式設計II

        else if (lastobj)  // reset the cursor as soon as we move off a non-swappable object

JavaScript進階程式設計II

            lastobj.style.cursor = 'pointer';

JavaScript進階程式設計II

        return false;

JavaScript進階程式設計II
JavaScript進階程式設計II
JavaScript進階程式設計II

    else ...{

JavaScript進階程式設計II

        // Sometimes can get stuck with no drop icon, so restore cursor just to be safe,

JavaScript進階程式設計II

        // when not dragging but passing over a draggable item

JavaScript進階程式設計II
JavaScript進階程式設計II

        if (isdraggable(obj))

JavaScript進階程式設計II

            obj.style.cursor = 'pointer';

JavaScript進階程式設計II
JavaScript進階程式設計II

        隻要移動滑鼠,我們就要首先檢查是否有對象被拖動。如果是,我們要計算對象應該被拖拽到的位置(畢竟,它自己不會像被施了魔法一樣跟随着滑鼠),然後移動對象到相應位置。這個公式主要保證從對象被點選開始,它的移動就要和滑鼠的移動保持一緻。我們還需要檢查是否正懸停在另外一個可拖拽對象上。若是,我們使用allowswap确定是否可以二者是否可以交換位置。如果不可以,就把滑鼠指針設為“等待”的形狀(可能會由于電腦的不同而呈現不同的形狀,但是這裡是标準的忙碌指針)。如果可以交換位置或者并不是在一個可拖拽對象上,我們就不管滑鼠指針的形狀,如果以前改變過就把它恢複原狀。

        注意,作為額外預防措施,如果沒有拖拽任何對象将滑鼠懸停在可拖拽對象上時,我們仍然将滑鼠指針恢複到正常狀态。這是因為有時滑鼠指針會停留在“等待”狀态,也要依賴于使用者移動滑鼠、釋放滑鼠按鍵有多快速,等等。這就是說,上面提到恢複滑鼠指針狀态的邏輯不是沒有道理的。

JavaScript進階程式設計II

// Callback when mouse is released - checks if a swap should occur and

JavaScript進階程式設計II

// returns dragged object to its starting position if not.

JavaScript進階程式設計II
JavaScript進階程式設計II

function mouseup(e)

JavaScript進階程式設計II
JavaScript進階程式設計II
JavaScript進階程式設計II
JavaScript進階程式設計II

    if (isdrag) ...{  // If something is being dragged

JavaScript進階程式設計II
JavaScript進階程式設計II

        // Get the object over which the mouse button was just released

JavaScript進階程式設計II
JavaScript進階程式設計II
JavaScript進階程式設計II

        // Check if mouse was release over an object we can swap with

JavaScript進階程式設計II
JavaScript進階程式設計II

        if (obj != dragobj && isdraggable(obj) && allowswap(dragobj, obj)) ...{

JavaScript進階程式設計II
JavaScript進階程式設計II

            // A swap is allowed - swap color, tooltip and contents of the

JavaScript進階程式設計II

            // dragged object with that it was released over

JavaScript進階程式設計II

            var htm = obj.innerHTML;

JavaScript進階程式設計II

            obj.innerHTML = dragobj.innerHTML;

JavaScript進階程式設計II

            dragobj.innerHTML = htm;

JavaScript進階程式設計II
JavaScript進階程式設計II

            var col = obj.style.color;

JavaScript進階程式設計II

            obj.style.color = dragobj.style.color;

JavaScript進階程式設計II

            dragobj.style.color = col;

JavaScript進階程式設計II
JavaScript進階程式設計II

            var titl = obj.title;

JavaScript進階程式設計II

            obj.title = dragobj.title;

JavaScript進階程式設計II

            dragobj.title = titl;

JavaScript進階程式設計II
JavaScript進階程式設計II

            // Set the position of the object we were dragging (dragobj) where the

JavaScript進階程式設計II

            // other object (obj) is located and move obj to the original location

JavaScript進階程式設計II

            // of dragobj before it was dragged (origx, origy).

JavaScript進階程式設計II

            dragobj.style.left = obj.style.left;

JavaScript進階程式設計II

            dragobj.style.top = obj.style.top;

JavaScript進階程式設計II

            obj.style.left = origx;

JavaScript進階程式設計II

            obj.style.top = origy;

JavaScript進階程式設計II
JavaScript進階程式設計II
JavaScript進階程式設計II

        else ...{

JavaScript進階程式設計II

            // No swap can occur so return dragged object to its starting position

JavaScript進階程式設計II

            dragobj.style.left = origx;

JavaScript進階程式設計II

            dragobj.style.top = origy;

JavaScript進階程式設計II
JavaScript進階程式設計II
JavaScript進階程式設計II

        // Restore cursor to pointer if it was changed in movemouse above

JavaScript進階程式設計II
JavaScript進階程式設計II

        if (lastobj) ...{

JavaScript進階程式設計II
JavaScript進階程式設計II
JavaScript進階程式設計II
JavaScript進階程式設計II

    isdrag = false;  // Nothing is being dragged now

JavaScript進階程式設計II

        如果在拖拽一個對象時釋放滑鼠,mouseup要做最多的外勤工作。如果在一個可拖拽對象上釋放滑鼠,我們使用allowswap判斷是否可以交換位置。如果可以,我們交換兩個對象的文本内容、顔色和提示(title屬性)。此時,你可能更願意交換它們的所有屬性,依目的而定。然後,我們移動被拖拽的對象到在其上釋放滑鼠的對象的位置,然後把該對象移動到被拖拽對象的原始位置。如此,就完成了位置交換。另一方面,如果不允許交換,我們隻需要把被拖拽的對象移動到它開始的位置。無論怎樣,如果在上面的movemouse中我們把滑鼠指針改為了“等待”狀态,就要回複正常情況,同時,我們要清除isdrag标志,表示目前沒有拖拽任何對象。

        最後,初始化對象非常容易。隻需要記住,可拖拽對象的id是由dragdrop開頭的:

JavaScript進階程式設計II

<table id="drag_drop" align="center" style="font-size:150%; color:green; background-color:#88ccff; white-space: nowrap;">

JavaScript進階程式設計II

    <tr>

JavaScript進階程式設計II
JavaScript進階程式設計II

            <span id="dragdropa" style="cursor: pointer; position: relative; color: #ff0000" title="John Doe">John</span>

JavaScript進階程式設計II
JavaScript進階程式設計II
JavaScript進階程式設計II
JavaScript進階程式設計II
JavaScript進階程式設計II

            <span id="dragdropb" style="cursor: pointer; position: relative; color: #a0522d" title="Jane Smith">Jane</span>

JavaScript進階程式設計II
JavaScript進階程式設計II
JavaScript進階程式設計II
JavaScript進階程式設計II
JavaScript進階程式設計II

            <span id="dragdropc" style="cursor: pointer; position: relative; color: #00aa00" title="Bill Schwartz">Bill</span>

JavaScript進階程式設計II
JavaScript進階程式設計II
JavaScript進階程式設計II

       放在表格中的對象,為了友善又使用不同的顔色表示,但是唯一重要的東西是可拖拽對象的id(它們在allowswap中被引用)以及可拖拽對象的style屬性中的position:relative。這個規則在JavaScript中慣于使用對象的相對定位計算它們的位置。還需要注意,外層的表格的id是drag_drop,在剛開始的window.onload函數中引用。

        總結

        但願前面的例子已經向你展示了div的一些創造性方式,可以用來切割或選擇性的展示網頁的部分内容。拖拽的例子隻是十分強大的概念的一個基礎例子,在今天多數的進階網頁上都可以見到。隻需再做一點工作,它就可以用來實作一個完全的可定制首頁,例如,你可以拖動和交換新聞feed、圖像和更多你内心的内容。唯一的限制,就是你的想象力!

繼續閱讀