欧美三区_成人在线免费观看视频_欧美极品少妇xxxxⅹ免费视频_a级毛片免费播放_鲁一鲁中文字幕久久_亚洲一级特黄

用 JavaScript 創建模塊化的交互用戶界面

系統 2766 0

級別: 中級

Greg Travis , 軟件工程師

2008 年 10 月 28 日

通過本文,了解使用拖放功能移動 Web 頁面的不同部分的技巧。分別實現交互性的不同方面,然后再將它們組合在一起,這樣便于靈活定制頁面,也讓您的 Web 用戶非常滿意。

JavaScript是一種功能強大的語言,可用于創建基于 Web的應用程序。它已經足夠穩定和成熟,完全可以創建與傳統桌面應用程序相抗衡的程序,因為后者在穩定性和特性豐富性方面都要勝出一籌。但JavaScript 最初只是用來向靜態 Web 頁面添加某些交互性,使它不再是靜態頁面,它現在還用于此目的。

我將要展示的這個技巧的關鍵之處是如何恰當地構建頁面,使它能與 JavaScript 代碼交互。通常,頁面都是通過頭腦里固有的 JavaScript代碼構造的。但是,盡管如此,很多時候您都需要向現有頁面內添加新的交互特性。而這往往需要一些技巧,因為 JavaScript代碼必須遍歷文檔結構并在合適的位置添加代碼,而且通常還要求不影響現有的結構 — 和頁面上已有的 JavaScript代碼。總之,要將對系統的影響最小化。

常見的縮寫詞
  • UI: 用戶界面
  • GUI: 圖形用戶界面
  • HTML: 超文本標記語言
  • XML: 可擴展標記語言
  • DOM: 文檔對象模型

可切換系統

本文介紹了一種方法,它通過移動頁面的不同部分來 激活 頁面。具體來講,就是通過將一個部分拖放到另一個部分之上從而實現 可切換 部分的切換。

要激活這些部分,只需向其添加 class 參數并加載一個 JavaScript 文件。可以通過向 <body> 標記添加 onload 方法來激活代碼,此方法會在頁面加載之后立即啟動代碼。代碼會處理隨后的事情。

注意: 本文示例所對應的源代碼可以從 下載 部分獲得。

此外,可以盡量多地使用抽象來構造代碼。程序的不同元素通常都不必要地相互纏結,UI 代碼更是這樣。可切換系統由不同的塊構建而成,每個塊實現交互性的不同部分。這些塊結合起來就能實現簡單無縫的界面,該界面對于 UI 的試驗和調優都很關鍵。



回頁首

可切換界面

可切換系統很容易使用。先由 Web 頁面設計人員將某些部分標志為可切換的。然后就可以在任何一個可切換元素上單擊并將該元素拖放到另一個可切換元素。放開鼠標按鈕后,這兩個元素就完成了交換。

為了能清楚展示所發生的事情,可以使用一些標準的 GUI 操作。

突出顯示被拖動的元素

當第一次單擊可切換元素時,在光標下面會出現一個透明的矩形。這個矩形由 coveringDiv() 函數創建,它剛好能覆蓋這個可切換元素。實際上是將這個矩形拖放到另一個元素。當拖放時,只有這個透明的矩形會移動 — 初始的元素保持不動直到鼠標按鈕被松開為止。

突出顯示拖動到的目標

另一個重要的操作是清晰標識出要拖動到的目標元素。當拖動透明的矩形四處移動時,光標可以經過多個可切換元素。當光標懸浮于某個可切換元素之上時,該元素就會通過另一個透明矩形突出顯示。這種突出顯示就能清楚地標示出此元素就是拖放到的目標。當松開鼠標按鈕時,被拖動的元素和拖放到的目標元素就會互換位置,而且所有透明矩形也會消失,直到下一次切換。

激活系統

正如先前提到的,必須要使代碼對已有系統影響最小。這就意味著頁面設計人員 —工作于 HTML 或 XML— 無需涉及可切換系統。這不是他們的工作。

此頁面只需具有如下三項內容:

  • JavaScript 標記
  • <body> 標記內的 onload 方法
  • 標記為 swappable 的可切換區域

JavaScript 標記

必須將以下標記置于頁面文件的頂部:

            <script src="rearrange-your-page.js"></script>

          

此標記在加載過程的早期加載,但它在 body 內的 onload 函數調用之后才會執行。

body 標記內的 Onload 方法

該方法在整個頁面加載時調用這個可切換系統。這一點很重要,因為此代碼的第一項功能就是在整個頁面內搜索可切換的元素。因而,需要確保這些元素已加載。body 內的 onload 方法應該如清單 1 所示。


清單 1. body 內的 onload 處理程序

            				
<body onload="swappable_start();">
    ... rest of page
  </body>

          

已標記為 swappable 的可切換區域

必須通過 class 參數這樣標記每個想要切換的區域。這是頁面作者和設計人員需要多加考慮的事情,因為他們需要將此參數添加給每個部分。參見清單 2。


清單 2. 用可切換類注釋 div

            				
<div class='swappable'>
    lorem ipsum lorem ipsum
  </div>

          

尋找可切換的部分

代碼所需做的首要事情是尋找頁面將被激活的部分。正如之前提到的,這只要求包圍這個部分的標記具有 class 參數。要尋找這些部分,需要找到所有具有可切換 class 的標記。此函數不是標準 DOM 庫的一部分,但它很容易實現。清單 3 展示了一個示例實現。


清單 3. getElementsByClass() 的實現

            				
// By Dustin Diaz
function getElementsByClass(searchClass,node,tag) {
        var classElements = new Array();
        if ( node == null )
                node = document;
        if ( tag == null )
                tag = '*';
        var els = node.getElementsByTagName(tag);
        var elsLen = els.length;
        var pattern = new RegExp("(^|////s)"+searchClass+"(////s|$)");
        for (i = 0, j = 0; i < elsLen; i++) {
                if ( pattern.test(els[i].className) ) {
                        classElements[j] = els[i];
                        j++;
                }
        }
        return classElements;
}

          

交互性的元素

程序一般是通過將各功能塊結合在一起而構建起來的。不同的程序員會有不同的實現方式,但作為一種規律,最好是采用多個小的功能塊而不是少數幾個大的功能塊。每個小功能塊應該實現一種功能并具有清楚的語義。

不過,在進行 GUI 編程時,這樣的構建不太容易。好的 GUI 必須調整很多界面元素并將它們的行為結合起來形成一個能直觀工作的整體行為。基于事件的系統通常都是由復雜的交換行為聯合起來的回調集合。模塊化的交互元素很難創建。

模塊化的交互元素

可切換代碼就使用了模塊化的交互元素。前面,我提到過在可切換系統內有兩種主要的交互元素:拖動元素的突出顯示和拖動到的目標的突出顯示。在代碼中,這兩個元素的實現是分開的。

本例很好地展示了模塊化處理交互性的技巧。正如可切換界面的描述中所提到的,這兩個交互性元素常常纏結在一起。突出顯示和突出顯示的消失都是在一個鼠標操作中發生的,而且它們的發生都對應鼠標輸入的不同方面。如果這兩個元素是在一個代碼片段中實現的,那么代碼可能不太容易讀懂,因為同時發生的事情很多。

拖動處理程序

為了使 GUI 的實現模塊化,我使用了 拖動處理程序 。這類似于內置在 GUI 系統的事件處理程序。雖然事件處理程序只處理某種單一事件,拖動處理程序卻可以處理整個拖放過程。一個拖動處理程序可處理一系列事件而不只一個單一事件。下面是拖動處理程序的示例骨架,如清單 4 所示。


清單 4. 拖動處理程序的骨架

            				
{
    start:
      function( x, y ) {
        // ...
      },

    move:
      function( x, y ) {
        // ...
      },

    done:
      function() {
        // ...
      },
  }

          

這個拖動處理程序是一個對象,具有三個方法: start move done 。當初始化一個拖放動作時,調用 start 方法并傳遞給這次單擊的對應坐標。當四處移動光標時,會反復調用 move 方法,然后同樣被傳遞給光標當前對應的坐標。最后,當鼠標按鈕釋放后,就會調用 done 方法。

可切換系統同時使用了兩個不同的拖動處理程序,這也讓您能夠干凈地處理交互的兩個不同方面,即便這兩個方面具有復雜的關系。讓其中的一個交互成為另一個交互的一部分并不合適。相反,應該能同時無縫地使用這兩個交互。

rectangle_drag_handler

這兩個拖放處理程序的其中是 rectangle_drag_handler 。此處理程序負責移動代表被拖動元素的透明矩形。清單 5 給出了這個 start 方法。


清單 5. rectangle_drag_handler 處理程序

            				
function rectangle_drag_handler( target )
  {
    this.start = function( x, y ) {
      this.cover = coveringDiv( target );
      make_translucent( this.cover, .6 );
      this.cover.style.backgroundColor = "#777";
      dea( this.cover );

      this.dragger = new dragger( this.cover, x, y );
    };
    // ...
  }

          

start 方法創建這個透明矩形并將其傳遞給另一個稱為 dragger 的對象。一個 dragger 就是一個對象,它能對應移動的光標移動 DOM 元素。可以將當前的光標的坐標傳遞給這個 dragger,它會更新所拖動的對象使其跟隨光標的移動。

move 方法更新這個 dragger,如清單 6 所示。


清單 6. 更新 dragger

            				
this.move = function( x, y ) {
    this.dragger.update( x, y );
  };

          

最后, done 方法(參見清單 7)刪除這個透明矩形,因為拖放過程現在已經結束。


清單 7. rectangle_drag_handler 的 done 方法

            				
this.move = function( x, y ) {
    this.done = function() {
      this.cover.parentNode.removeChild( this.cover );
    };
}

          

組合拖動處理程序

現在必須找到一種方法來同時使用這兩個拖動處理程序。這可以通過 compose_drag_handlers() 函數輕松實現,該函數接受這兩個拖動處理程序并將其結合成一個綜合的拖動處理程序。這個綜合拖動處理程序的使用與一般的拖動處理程序一樣。這樣,這兩個原始的拖動處理程序的行為就實現了無縫結合。

compose_drag_handlers() 函數很容易編寫。它看上去很像是一個拖動處理程序,但每個方法都會調用這兩個原始拖動處理程序中相應的方法。這個函數如清單 8 所示。


清單 8. compose_drag_handlers()

            				
function compose_drag_handlers( a, b )
  {
    return {
    start:
      function( x, y ) {
        a.start( x, y );
        b.start( x, y );
      },

    move:
      function( x, y ) {
        a.move( x, y );
        b.move( x, y );
      },

    done:
      function() {
        a.done();
        b.done();
      },
    }
  }

          

正如您所見,拖動處理程序 a b 被組合到一個綜合的拖動處理程序內。如果要調用這個綜合處理程序的 start() 方法,實際上就是先后調用 a.start() b.start()

您需要在名為 prepare_swappable() 的設置函數內調用 compose_drag_handlers ,如清單 9 所示。


清單 9. prepare_swappable() 函數

            				
function prepare_swappable( o )
  {
    swappables.push( o );
    var sdp = new rectangle_drag_handler( o );
    var hdp = new highlighting_drag_handler( o );
    var both = compose_drag_handlers( sdp, hdp );
    install_drag_handler( o, both );
  }

          

除了其他功能之外,此函數最主要的功能是為可切換元素創建 rectangle_drag_handler highlighting_drag_handler ,然后再將它們組合成一個綜合的拖動處理程序。最后,這個綜合拖動處理程序再通過調用 install_drag_handler() 來激活,這將在接下來的兩個小節中詳細介紹。

安全安裝鼠標處理程序

與常規的事件處理程序不同,一個拖動處理程序可以處理多個事件。盡管如此,它還是需要附加到對象,這與常規的事件處理程序相同。

安裝任何一種事件處理程序都是需要技巧的,因為正在修改的元素很可能已經在其內安裝了事件處理程序。如果要替換這些事件處理程序,就需要更改頁面的行為方式。

為了避免這一問題,可以使用一個名為 install_mouse_handlers() 的實用函數,如清單 10 所示。


清單 10. install_mouse_handlers() 函數

            				
function install_mouse_handlers( target, onmouseup, onmousedown, onmousemove )
  {
    var original_handlers = {
      onmouseup: target.onmouseup,
      onmousedown: target.onmousedown,
      onmousemove: target.onmousemove
    };

    target.onmouseup = onmouseup;
    target.onmousedown = onmousedown;
    target.onmousemove = onmousemove;

    return {
      restore: function() {
        target.onmouseup = original_handlers.onmouseup;
        target.onmousedown = original_handlers.onmousedown;
        target.onmousemove = original_handlers.onmousemove;
       }
    };
  }

          

install_mouse_handlers() 函數負責向特定的對象添加特定的鼠標處理程序。它返回的是一個對象,可使用該對象恢復原始的處理程序。這樣一來,當拖放過程結束后,就可以調用 restore() 函數,恢復到拖放過程開始之前的狀態。

激活拖動處理程序

針對拖放操作的拖動處理程序使用了這三個鼠標處理程序: onmousedown onmouseup onmousemove 。不過,開始時,只需安裝 mousedown 處理程序,因為此時您尚在等待激發初始化拖放過程的單擊。

當單擊發生時,就需要安裝 mousemove mouseup 處理程序。而且,在此時,不再需要 mousedown 處理程序,因為已經進行單擊。該處理程序將被刪除,在拖放過程完成后再恢復它。最初的 mousedown 處理程序如清單 11 所示。


清單 11. 最初的 mousedown 處理程序

            				
var onmousedown = function( e ) {
    var x = e.clientX;
    var y = e.clientY;

    p.start( x, y );

    var target_handler_restorer = null;
    var document_handler_restorer = null;

    var onmousemove = function( e ) {
      var x = e.clientX;
      var y = e.clientY;

      p.move( x, y );
    };

    var onmouseup = function( e ) {
      p.done();
      target_handler_restorer.restore();
      document_handler_restorer.restore();
    };

    target_handler_restorer =
      install_mouse_handlers( target, onmouseup, null, onmousemove );
    document_handler_restorer =
      install_mouse_handlers( document, onmouseup, null, onmousemove );

    e.stopPropagation();

    return false;
  };

          

在初始化拖放序列并調用此處理程序時,它會創建 onmousemove onmouseup 處理程序并能在目標元素內安裝它們。當然,它還會使用一個 install_mouse_handlers() ,以便以后的卸載。

還有一點需要注意:是在 document 對象內安裝這些處理程序的。這一點十分關鍵,因為在拖放過程中用戶可能會將光標拖過整個頁面。如果鼠標超出可切換元素的范圍 — 您很可能還想收到這些事件。同樣地,可以使用 install_mouse_handlers() 以便以后恢復它們。



回頁首

將它們組合起來

至此,我已經介紹了很多不同的類和函數。其中的每一個類或函數本身都十分簡單,因此更重要的是要了解它們是如何協同工作的。

下面是對整個拖放過程的一個總結:

  • 單擊一個可切換元素。
  • 此元素的 onmousedown 處理程序將被調用,它安裝 onmousemove onmouseup 處理程序。
  • 移動鼠標,這些處理程序將被調用。
  • 這些處理程序反過來調用前面安裝的拖動處理程序。
  • 這個拖動處理程序實際上是一個復合拖動處理程序,綜合了兩個不同的拖動處理程序的效果。
  • 其中的一個拖動處理程序 rectangle_drag_handler 負責向光標附加一個代表被拖動元素的透明矩形。
  • 另一個拖動處理程序 highlighting_drag_handler 負責突出顯示鼠標移過的那些可切換元素,以顯示可以進行元素拖動的地方。
  • 當在目標元素之上釋放鼠標按鈕時, highlighting_drag_handler done() 方法就會切換這兩個元素。這個拖動處理程序將被卸載,只留下最初的 onmousedown 處理程序,準備好開始下一輪的拖放過程。



回頁首

結束語

拖放操作相對簡單,但它涉及了幾個交互過程,用來跟蹤整個過程的用戶輸入和提供即時反饋。本文展示如何將模塊化的交互元素組合成統一整體來構建完整的 GUI。

這種做法有很多好處。由于代碼是模塊化的,因此更容易編寫和維護。所需的函數和類的代碼沒有一個是超過 40 行的,并且它們通常更短。

每一個交互元素都會實現一個典型的 GUI 過程或效果,所以可在其他上下文中重用它們。可以開發這些交互元素的豐富的庫,從而通過組合各個部分構建更復雜的 UI。

用 JavaScript 創建模塊化的交互用戶界面


更多文章、技術交流、商務合作、聯系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯系: 360901061

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對您有幫助就好】

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長會非常 感謝您的哦!!!

發表我的評論
最新評論 總共0條評論
主站蜘蛛池模板: 久久久久亚洲视频 | 九九热在线视频免费观看 | 久久亚洲精品国产精品婷婷 | 亚洲国产综合久久精品 | 国产精品九九久久99视频 | 美女下面被cao出水 玖玖玖影院 | 91美女在线观看 | 狠狠干成人 | 国产成人无码网站m3u8 | 成年视频网站免费观看 | 丁香狠狠 | 91精品久久久 | 都市妖奇谈 电视剧 | xx免费视频 | 国产精品冒白浆免费视频 | 久久高清免费视频 | 亚洲国产专区 | 欧美精品亚洲一区二区在线播放 | 一区二区三区四区视频 | 妞干网在线观看 | 久爱青草视频在线观看 | 国产91亚洲精品 | 中文字幕不卡在线观看 | 国产国产成人久久精品杨幂 | 日韩在线观看一区二区不卡视频 | 草久免费| 成人在线精品视频 | 婷婷色在线| 久久综合九色综合97欧美 | 久久99精品这里精品动漫6 | 午夜免费观看福利片一区二区三区 | 中文字幕网在线 | 欧美13videosex性极品 | 一级黄色毛片视频 | 亚洲第一天堂 | 美女吊逼 | 亚洲精品无码成人A片九色播放 | 天堂精品| 日韩在线观看毛片 | 中文字幕成人乱码在线电影 | 亚洲精品成人 |