ExtJsソースの分析と学習-ExtJsイベントメカニズム(5)


最近ずっと製品を作るのに忙しいので、長い間文章を書いていません.次はExtJsのイベントメカニズムの最後の内容を書き終わります.主にExtが提供する3つのアシストインプリメンテーションイベントクラス、ショートカットキー、ナビゲーションキー、マウスボタンイベントについて説明します.
 
ショートカットキーExt.KeyMapこの機能の実装はクラスExt.KeyMapにカプセル化される
Ext.KeyMap = function(el, config, eventName){
    this.el  = Ext.get(el);
    this.eventName = eventName || "keydown";
    this.bindings = [];
    if(config){
        this.addBinding(config);
    }
    this.enable();
};

このクラスの実装は3つのステップに分けられ、まずショートカットキーを登録する要素elを見つけ、configパラメータをイベントのリスニング関数thisに変換する.addBinding(config)は、最後にリスニング関数thisを登録する.enable().まずaddBindingメソッドの実装を見てみましょう
 
addBinding : function(config){
        if(Ext.isArray(config)){
            Ext.each(config, function(c){
                this.addBinding(c);
            }, this);
            return;
        }
        var keyCode = config.key,
            fn = config.fn || config.handler,
            scope = config.scope;

	if (config.stopEvent) {
	    this.stopEvent = config.stopEvent;    
	}	

        if(typeof keyCode == "string"){
            var ks = [];
            var keyString = keyCode.toUpperCase();
            for(var j = 0, len = keyString.length; j < len; j++){
                ks.push(keyString.charCodeAt(j));
            }
            keyCode = ks;
        }
        var keyArray = Ext.isArray(keyCode);
        
        //           ,       fn/handle          
        var handler = function(e){
        	//    'shift', 'ctrl', 'alt',            'shift', 'ctrl', 'alt',        
            if(this.checkModifiers(config, e)){
                var k = e.getKey();
                if(keyArray){
                    for(var i = 0, len = keyCode.length; i < len; i++){
                        if(keyCode[i] == k){
                          if(this.stopEvent){
                              e.stopEvent();
                          }
                          fn.call(scope || window, k, e);
                          return;
                        }
                    }
                }else{
                    if(k == keyCode){
                        if(this.stopEvent){
                           e.stopEvent();
                        }
                        fn.call(scope || window, k, e);
                    }
                }
            }
        };
        this.bindings.push(handler);
	},

 
configコンフィギュレーション・アイテムは、次のプロパティ・タイプ記述をサポートします.--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ft押下同時処理key(デフォルトfalse)ctrl Boolean True:ctrl押下のみ同時処理key(デフォルトfalse)handler Function KeyMapが所望の組合せキーを見つけたときに実行される関数alt Boolean True:alt押下のみ同時処理key(デフォルトfalse)fn Function結合キーを押すとコールバック関数scope Objectコールバック関数の役割ドメインstopEvent Booleanはイベントの泡立ちを停止し、要素のデフォルト行を阻止するために使用されます.enableメソッドを参照して、イベントを要素に登録します.
 
enable: function(){
		if(!this.enabled){
		    this.el.on(this.eventName, this.handleKeyDown, this);
		    this.enabled = true;
		}
	},

指定したel要素のイベント例を登録します:よく使うコピー、切り取り、貼り付けの実装
 
var config = [{//  
		key : 'x',
		ctrl : true,
		fn : function() {
			//cut
		},
		scope : this
	},{//  
		key : 'c',
		ctrl : true,
		fn : function() {
			//copy
		},
		scope : this
	},{//  
		key : 'v',
		ctrl : true,
		fn : function() {
			//paste
		},
		scope : this
	},{//  
		key : 'abcdefghigklmnopqrstuvwxyz0123456789',
		ctrl : false,
		shift : false,
		alt : false,
		fn : function(k, e) {
			alert(k);
		},
		scope : this
	}];

var map = new Ext.KeyMap("my-element", config);

 
ナビゲーションキーExt.KeyNav
 
ナビゲーションキーの実装はクラスExt.KeyNavにカプセル化され,まずその構造関数を見る.
 
 
Ext.KeyNav = function(el, config){
    this.el = Ext.get(el);
    Ext.apply(this, config);
    if(!this.disabled){//        
        this.disabled = true;
        this.enable();//      
    }
};

リスニング関数の登録を参照
 
   enable: function() {
        if (this.disabled) {
            if (Ext.isSafari2) {
                // call stopKeyUp() on "keyup" event
                this.el.on('keyup', this.stopKeyUp, this);
            }

            this.el.on(this.isKeydown()? 'keydown' : 'keypress', this.relay, this);
            this.disabled = false;
        }
    },

IEや他のブラウザのkeyPressイベントでは、アルファベット以外の数字キーがバブルされないため、keyPressイベントの代わりにkeyDownイベントが使用されます.このイベントの処理関数relayはエージェントとして機能します
 
relay : function(e){
        var k = e.getKey(),
            h = this.keyToHandler[k];
        if(h && this[h]){
            if(this.doRelay(e, this[h], h) !== true){
                e[this.defaultEventAction]();
            }
        }
    },

 
KeyToHandlerは、キー名とキー値に対応するhashテーブルであり、eventオブジェクトを介してキー値を取得した後、Ext.KeyNavクラスの12のナビゲーションキー名と比較して、ナビゲーションキーであるかどうかを確認し、もしそうであれば、登録されている処理関数があるかどうかを確認して、リスニング関数を実行します.このナビゲーションキーは12個あり、それぞれkeyToHandler:{37:“left”,39:“right”,38:“up”,40:“down”,33:“pageUp”,34:“pageDown”,46:“del”,36:“home”,35:“end”,13:“enter”,27:“esc”,9:「tab」},例
 
var nav = new Ext.KeyNav("my-element", {
    "left" : function(e){
        this.moveLeft(e.ctrlKey);
    },
    "right" : function(e){
        this.moveRight(e.ctrlKey);
    },
    "enter" : function(e){
        this.save();
    },
    scope : this
});

 
イベントをマウスで押したままにします.ClickRepeater
マウスを押すイベントは、ある要素をマウスで押すことで、指定した時間間隔で同じ動作を繰り返します.この機能の実現はクラスExt.utilにカプセル化する.ClickRepeater、まず構造関数を見てみましょう
 
constructor : function(el, config){
        this.el = Ext.get(el);
        this.el.unselectable();//        

        Ext.apply(this, config);

        this.addEvents(
        /**
         * @event mousedown
         *           。
         * Fires when the mouse button is depressed.
         * @param {Ext.util.ClickRepeater} this
         * @param {Ext.EventObject} e
         */
        "mousedown",
        /**
         * @event click
         *                    , mousedown   。
         * Fires on a specified interval during the time the element is pressed.
         * @param {Ext.util.ClickRepeater} this
         * @param {Ext.EventObject} e
         */
        "click",
        /**
         * @event mouseup
         *         。
         * Fires when the mouse key is released.
         * @param {Ext.util.ClickRepeater} this
         * @param {Ext.EventObject} e
         */
        "mouseup"
        );

        if(!this.disabled){
            this.disabled = true;
            this.enable();
        }

        // allow inline handler
        if(this.handler){
            this.on("click", this.handler,  this.scope || this);
        }

        Ext.util.ClickRepeater.superclass.constructor.call(this);        
},

このコンストラクション関数でthisが呼び出されます.enable();をクリックしてイベントを処理し、コンフィギュレーション・アイテムがhandler処理関数を宣言するとcilckイベントに登録されます.次に見る方法enable
 
enable: function(){
        if(this.disabled){
            this.el.on('mousedown', this.handleMouseDown, this);
            if (Ext.isIE){
                this.el.on('dblclick', this.handleDblClick, this);
            }
            if(this.preventDefault || this.stopDefault){
                this.el.on('click', this.eventOptions, this);
            }
        }
        this.disabled = false;
    },

このメソッドでは要素elにmousedownイベントを登録し、IEブラウザであればdblickイベントも登録し、構成項目に基づいてデフォルトまたはバブル処理を阻止します.handleMouseDownを参照してください.
 
handleMouseDown : function(e){
        clearTimeout(this.timer);
        this.el.blur();//    
        if(this.pressClass){
            this.el.addClass(this.pressClass);
        }
        this.mousedownTime = new Date();

        Ext.getDoc().on("mouseup", this.handleMouseUp, this);
        this.el.on("mouseout", this.handleMouseOut, this);

        this.fireEvent("mousedown", this, e);
        this.fireEvent("click", this, e);

        // Do not honor delay or interval if acceleration wanted.
        if (this.accelerate) {
            this.delay = 400;
        }
        this.timer = this.click.defer(this.delay || this.interval, this, [e]);
},

ユーザがある要素でマウスを押すと、まずその要素に焦点を失わせ、スタイルを変更するとともに、マウスボタンをそれぞれ離したり移動したりしてリスニング関数を登録し、最後に指定した間隔でclick関数の実行を遅らせる
 
click : function(e){
        this.fireEvent("click", this, e);
        this.timer = this.click.defer(this.accelerate ?
            this.easeOutExpo(this.mousedownTime.getElapsed(),
                400,
                -390,
                12000) :
            this.interval, this, [e]);
},

 
この関数はclick関数を再帰的に呼び出し、thisが設定されている場合.accelerateでは、時間間隔が一定のアルゴリズムで実行されるほど短くなり、clickの実行が速くなります.