オリジナルドラッグ&ドロップ実装

8459 ワード

イベント操作ツールの定義
let EventUtil = new Object;
/*              ,oTarget     ,sEventType     , click、keydown ,fnHandler       */
EventUtil.addEventHandler = function (oTarget, sEventType, fnHandler) {
     // firefox   
     if (oTarget.addEventListener) {
         oTarget.addEventListener(sEventType, fnHandler, false);
     }
     // IE 
     else if (oTarget.attachEvent) {
         oTarget.attachEvent("on" + sEventType, fnHandler);
     }
     else {
         oTarget["on" + sEventType] = fnHandler;
     }
};
/*                ,oTarget     ,sEventType     , click、keydown ,fnHandler       */      
EventUtil.removeEventHandler = function (oTarget, sEventType, fnHandler) {
     if (oTarget.removeEventListener) {
         oTarget.removeEventListener(sEventType, fnHandler, false);
     } else if (oTarget.detachEvent) {
         oTarget.detachEvent("on" + sEventType, fnHandler);
     } else {
         oTarget["on" + sEventType] = null;
     }
};

/*     ,  IE                            ,              */
EventUtil.formatEvent = function (oEvent) {
     // isIE isWin     js  ,            
     if (isIE && isWin) {
         oEvent.charCode = (oEvent.type == "keypress") ? oEvent.keyCode : 0;
         // IE     ,     
         oEvent.eventPhase = 2;
         oEvent.isChar = (oEvent.charCode > 0);
         oEvent.pageX = oEvent.clientX + document.body.scrollLeft;
         oEvent.pageY = oEvent.clientY + document.body.scrollTop;
         //          
         oEvent.preventDefault = function () {
             this.returnValue = false;
         };

          //  toElement,fromElement      relatedTarget
         if (oEvent.type == "mouseout") {
             oEvent.relatedTarget = oEvent.toElement;
         } else if (oEvent.type == "mouseover") {
             oEvent.relatedTarget = oEvent.fromElement;
         }
         //          
         oEvent.stopPropagation = function () {
             this.cancelBubble = true;
         };

         oEvent.target = oEvent.srcElement;
         //           ,IE  
         oEvent.time = (new Date).getTime();
     }
     return oEvent;
};

EventUtil.getEvent = function() {
     if (window.event) {
         //    IE   
         return this.formatEvent(window.event);
     } else {
         return EventUtil.getEvent.caller.arguments[0];
     }
};

詳細カスタムイベント-オブザーバ:
function EventTarget(){
    this.handlers = {};
}
EventTarget.prototype = {
    constructor: EventTarget,
    addHandler: function(type, handler){
        if (typeof this.handlers[type] == "undefined"){
            this.handlers[type] = [];
        }
        this.handlers[type].push(handler);
    },
    fire: function(event){
        if (!event.target){
            event.target = this;
        }
        if (this.handlers[event.type] instanceof Array){
            let handlers = this.handlers[event.type];
            for (var i=0, len=handlers.length; i < len; i++){
                handlers[i](event);
            }
        }
    },
    removeHandler: function(type, handler){
        if (this.handlers[type] instanceof Array){
            let handlers = this.handlers[type];
            for (var i=0, len=handlers.length; i < len; i++){
                if (handlers[i] === handler){
                    break;
                }
            }
            handlers.splice(i, 1);
        }
    }
};

EventTargetタイプには、イベントハンドラを格納するための個別のプロパティhandlersがあります.もう3つの方法があります.
addHandler() ,                 ;
fire() ,        ;
removeHandler() ,                 。

  • addHandler()メソッドは、イベントタイプとイベントを処理するための関数の2つのパラメータを受け入れます.メソッドを呼び出すと、handlersプロパティにイベントタイプの配列がすでに存在するかどうかを確認します.ない場合は、新しいものを作成します.次にpush()を使用して、配列の末尾にプロセッサを追加します.イベントをトリガーする場合はfire()関数を呼び出します.この方法は、少なくともtype属性を含むオブジェクトである個別のパラメータを受け入れます.
  • fire()メソッドは、eventオブジェクトにtargetプロパティを設定します.まだ指定されていない場合は.次に、イベントタイプに対するプロセッサのセットを検索し、各関数を呼び出し、eventオブジェクトを与えます.これらはカスタムイベントなので、eventオブジェクトに必要な追加情報は自分で決めます.
  • removeHandler()メソッドはaddHandler()の補助であり、それらが受け入れるパラメータは同じである:イベントのタイプとイベントハンドラ.このメソッドは、イベントハンドラの配列を検索して、削除するハンドラの場所を見つけます.見つかった場合はbreakオペレータを使用してforループを終了します.次にsplice()メソッドを使用して、そのアイテムを配列から削除します.

  • ドラッグ&ドロップ関数を定義するには、次の手順に従います.
    let DragDrop = function(){
        let dragdrop = new EventTarget();
        let dragging = null;
        let diffx = 0;
        let diffy = 0;
        function handleEvent(event){
            //        
            event = EventUtil.getEvent(event);
            let target = EventUtil.getTarget(event);
            //       
            switch(event.type){
                case "mousedown":
                    if (target.className.indexOf("draggable") > -1){
                        dragging = target;
                        diffx = event.clientX - target.offsetLeft;
                        diffy = event.clientY - target.offsetTop;
                        dragdrop.fire({type:"dragstart", target: dragging, x: event.clientX, y: event.clientY});
                    }
                    break;
                case "mousemove":
                    if (dragging !== null){
                        //     
                        dragging.style.left = (event.clientX - diffx) + "px";
                        dragging.style.top = (event.clientY - diffy) + "px";
                        //        
                        dragdrop.fire({type:"drag", target: dragging, x: event.clientX, y: event.clientY});
                    }
                    break;
                case "mouseup":
                    dragdrop.fire({type:"dragend", target: dragging, x: event.clientX, y: event.clientY});
                    dragging = null;
                    break;
            }
        };
        //    
        dragdrop.enable = function(){
            EventUtil.addHandler(document, "mousedown", handleEvent);
            EventUtil.addHandler(document, "mousemove", handleEvent);
            EventUtil.addHandler(document, "mouseup", handleEvent);
        };
        dragdrop.disable = function(){
            EventUtil.removeHandler(document, "mousedown", handleEvent);
            EventUtil.removeHandler(document, "mousemove", handleEvent);
            EventUtil.removeHandler(document, "mouseup", handleEvent);
        };
        return dragdrop;
    }();

    DragDropオブジェクトはドラッグアンドドロップのすべての基本機能をカプセル化しています.これは単一のオブジェクトであり、モジュールモードを使用して実装の詳細を非表示にします.dragging変数は最初はnullであり、ドラッグされた要素が格納されるので、その変数がnullでない場合、ドラッグしていることがわかります.handleEvent()関数は、ドラッグ&ドロップ機能のすべての3つのマウスイベントを処理します.イベントオブジェクトとイベントターゲットの参照を最初に取得します.その後、switch文を使用して、どのイベントスタイルをトリガーするかを決定します.mousedownイベントが発生すると、targetのclassに「draggable」クラスが含まれているかどうかを確認し、もしそうであればtargetをdraggingに格納します.このテクニックは、JavaScriptスクリプトではなくタグ言語でドラッグ可能な要素を簡単に決定できます.
    handleEvent()のmousemoveの場合は前のコードと同じですが、draggingがnullであるかどうかを確認します.nullでない場合、draggingはドラッグする要素であることがわかり、適切な位置に配置されます.mouseupの場合はdraggingをnullにリセットし、mousemoveイベントでの判断を失効させるだけです.
    DragDropには、enable()とdisable()の2つの共通の方法があります.これらは、すべてのイベントハンドラを追加および削除するだけです.この2つの関数は、ドラッグ&ドロップ機能の追加の制御手段を提供します.
    DragDropオブジェクトを使用するには、これらのコードをページに含めてenable()を呼び出します.ドラッグアンドドロップは、次の例で示すように、draggableクラスを含むすべての要素に対して自動的に有効になります.

    エレメントがドラッグ&ドロップできるように、絶対的に位置決めされている必要があります.
    DragDrop.addHandler("dragstart", function(event){
        let status = document.getElementById("status");
        status.innerHTML = "Started dragging " + event.target.id;
    });
    
    DragDrop.addHandler("drag", function(event){
        let status = document.getElementById("status");
        status.innerHTML += "
    Dragged " + event.target.id + " to (" + event.x +"," + event.y + ")"; }); DragDrop.addHandler("dragend", function(event){ let status = document.getElementById("status"); status.innerHTML += "
    Dropped " + event.target.id + " at (" + event.x +"," + event.y + ")"; });

    このコードは、dragstart、drag、dragendの3つのイベントを定義します.いずれもドラッグされた要素をtargetに設定し、現在の位置を表すx属性とy属性を与えます.dragdropオブジェクトにトリガーされ、オブジェクトに戻る前にenable()メソッドとdisable()メソッドを追加します.これらのモジュールモードの細かい変更によりDragDropオブジェクトはイベントをサポートする.
    ここでは、DragDropオブジェクトの各イベントにイベントハンドラを追加します.ドラッグされた要素の現在の状態と位置を実現するために、要素も使用されます.要素が置かれると、最初にドラッグされた後に通過するすべての中間ステップが表示されます.
    DragDropにカスタムイベントを追加すると、ネットワークアプリケーションで複雑なドラッグアンドドロップ機能を処理できるようになります.