亚洲免费在线-亚洲免费在线播放-亚洲免费在线观看-亚洲免费在线观看视频-亚洲免费在线看-亚洲免费在线视频

用 JavaScript 創(chuàng)建模塊化的交互用戶界面

系統(tǒng) 2666 0

級別: 中級

Greg Travis , 軟件工程師

2008 年 10 月 28 日

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

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

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

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

可切換系統(tǒng)

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

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

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

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



回頁首

可切換界面

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

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

突出顯示被拖動的元素

當?shù)谝淮螁螕艨汕袚Q元素時,在光標下面會出現(xiàn)一個透明的矩形。這個矩形由 coveringDiv() 函數(shù)創(chuàng)建,它剛好能覆蓋這個可切換元素。實際上是將這個矩形拖放到另一個元素。當拖放時,只有這個透明的矩形會移動 — 初始的元素保持不動直到鼠標按鈕被松開為止。

突出顯示拖動到的目標

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

激活系統(tǒng)

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

此頁面只需具有如下三項內(nèi)容:

  • JavaScript 標記
  • <body> 標記內(nèi)的 onload 方法
  • 標記為 swappable 的可切換區(qū)域

JavaScript 標記

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

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

          

此標記在加載過程的早期加載,但它在 body 內(nèi)的 onload 函數(shù)調(diào)用之后才會執(zhí)行。

body 標記內(nèi)的 Onload 方法

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


清單 1. body 內(nèi)的 onload 處理程序

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

          

已標記為 swappable 的可切換區(qū)域

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


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

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

          

尋找可切換的部分

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


清單 3. getElementsByClass() 的實現(xiàn)

            				
// 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;
}

          

交互性的元素

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

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

模塊化的交互元素

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

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

拖動處理程序

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


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

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

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

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

          

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

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

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 方法創(chuàng)建這個透明矩形并將其傳遞給另一個稱為 dragger 的對象。一個 dragger 就是一個對象,它能對應移動的光標移動 DOM 元素。可以將當前的光標的坐標傳遞給這個 dragger,它會更新所拖動的對象使其跟隨光標的移動。

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


清單 6. 更新 dragger

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

          

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


清單 7. rectangle_drag_handler 的 done 方法

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

          

組合拖動處理程序

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

compose_drag_handlers() 函數(shù)很容易編寫。它看上去很像是一個拖動處理程序,但每個方法都會調(diào)用這兩個原始拖動處理程序中相應的方法。這個函數(shù)如清單 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 被組合到一個綜合的拖動處理程序內(nèi)。如果要調(diào)用這個綜合處理程序的 start() 方法,實際上就是先后調(diào)用 a.start() b.start()

您需要在名為 prepare_swappable() 的設置函數(shù)內(nèi)調(diào)用 compose_drag_handlers ,如清單 9 所示。


清單 9. prepare_swappable() 函數(shù)

            				
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 );
  }

          

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

安全安裝鼠標處理程序

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

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

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


清單 10. install_mouse_handlers() 函數(shù)

            				
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() 函數(shù)負責向特定的對象添加特定的鼠標處理程序。它返回的是一個對象,可使用該對象恢復原始的處理程序。這樣一來,當拖放過程結(jié)束后,就可以調(diào)用 restore() 函數(shù),恢復到拖放過程開始之前的狀態(tài)。

激活拖動處理程序

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

當單擊發(fā)生時,就需要安裝 mousemove mouseup 處理程序。而且,在此時,不再需要 mousedown 處理程序,因為已經(jīng)進行單擊。該處理程序?qū)⒈粍h除,在拖放過程完成后再恢復它。最初的 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;
  };

          

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

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



回頁首

將它們組合起來

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

下面是對整個拖放過程的一個總結(jié):

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



回頁首

結(jié)束語

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

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

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

用 JavaScript 創(chuàng)建模塊化的交互用戶界面


更多文章、技術交流、商務合作、聯(lián)系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯(lián)系: 360901061

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

【本文對您有幫助就好】

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

發(fā)表我的評論
最新評論 總共0條評論
主站蜘蛛池模板: 亚洲一级毛片欧美一级说乱 | 久久久亚洲国产精品主播 | 亚洲欧美国产日产综合不卡 | 亚洲国产精品综合欧美 | 国产福利一区二区三区在线视频 | 久久国产精品视频一区 | 91在线精品视频 | 欧美18videosex灌满 | 午夜精品久久影院蜜桃 | 中国一级特黄高清免费的大片 | 涩涩色中文综合亚洲 | 黄在线观看网站 | 日韩精品成人 | 国产一区国产二区国产三区 | 国产99在线a视频 | 91亚洲国产成人久久精品网址 | 九九热精品国产 | 天天射综合网站 | 色综七七久久成人影 | 久久这里只有精品视频99 | 亚洲国产精品免费在线观看 | 国产一区二区三区久久精品小说 | 99视频久久精品久久 | 国产精选一区二区 | xxxx日本在线播放免费不卡 | 热久久国产 | 91情国产l精品国产亚洲区 | 日本免费一级视频 | 第四色激情网 | 亚洲香蕉毛片久久网站老妇人 | 亚洲欧美二区三区久本道 | 日韩精品中文字幕在线观看 | 97在线播放 | 欧美日韩色综合网站 | 日韩欧美在线观看成人 | 香蕉亚洲欧洲在线一区 | 国产精品品福利视频 | 亚洲国产精品欧美日韩一区二区 | 国产欧美乱码在线看 | 亚州激情视频在线播放 | 亚洲国产一区二区三区四区 |