ExtJs源码分析与学习—遮罩层

类Ext.LoadMask

      这一节分析Ext中遮罩效果的实现,Ext中专门为遮罩效果提供了类Ext.LoadMask,该类封装了Ext.Element中实现遮罩的方法mask和unmask(这两个方法的定义在源文件Element.fx-more.js中)。该类用于在加载数据时为元素做出类似于遮罩的效果。如果配置了Ext.data.Store,则可将效果与Ext.data.Store的加载达到同步,并且mask本身也会被缓存起来从而可以为其他加载复用。对于所有的元素(Element),这个遮罩类会替换元素本身的Updater加载指示器,并且在初始化完毕后销毁。

      先看Element.fx-more.js中的方法mask和unmask

/**
             * 在元素上加入一个遮罩来禁止用户操作,该效果依赖于core.css
             * 这个方法只能用于可接受子节点的元素上
             * Puts a mask over this element to disable user interaction. Requires core.css.
             * This method can only be applied to elements which accept child nodes.
             * @param {String} msg (optional) A message to display in the mask 遮罩时的提示信息
             * @param {String} msgCls (optional) A css class to apply to the msg element 遮罩元素的css样式
             * @return {Element} The mask element 返回遮罩蒙板元素
             */
            mask : function(msg, msgCls) {
                var me  = this,
                    dom = me.dom,
                    dh  = Ext.DomHelper,
                    EXTELMASKMSG = "ext-el-mask-msg",
                    el,
                    mask;
				
                //如果是非body,并且该元素的样式position为static时,需要把应用遮罩效果的元素设为relative
                //这里需要说一下position,该样式属性可以把元素放置到一个静态的、相对的、绝对的、或固定的位置中
           /**
                 *  值	                描述
	static	    默认。位置设置为 static 的元素,它始终会处于页面流给予的位置(static 元素会忽略任何 top、bottom、left 或 right 声明)。
	relative	    位置被设置为 relative 的元素,可将其移至相对于其正常位置的地方,因此 "left:20" 会将元素移至元素正常位置左边 20 个像素的位置。
	absolute	    位置设置为 absolute 的元素,可定位于相对于包含它的元素的指定坐标。此元素的位置可通过 "left"、"top"、"right" 
		    以及 "bottom" 属性来规定。
	fixed	    位置被设置为 fixed 的元素,可定位于相对于浏览器窗口的指定坐标。此元素的位置可通过 "left"、"top"、"right" 
		    以及"bottom" 属性来规定。不论窗口滚动与否,元素都会留在那个位置。工作于 IE7(strict 模式)。
           */
                if (!(/^body/i.test(dom.tagName) && me.getStyle('position') == 'static')) {
                    me.addClass(XMASKEDRELATIVE);
                }
                //先删除element maskMsg 和 mask,从Element缓存中取得
                if (el = data(dom, 'maskMsg')) {
                    el.remove();
                }
                if (el = data(dom, 'mask')) {
                    el.remove();
                }
	//添加新的遮罩层,样式ext-el-mask默认透明度为0.5,z-index为100,这样如果被遮罩的元素z-index高于100,就不能起到遮罩的效果了
           //要想达到该效果,只需重新设置z-index即可,mask.setStyle('z-index',1000);
                mask = dh.append(dom, {cls : "ext-el-mask"}, true);
                data(dom, 'mask', mask);

                me.addClass(XMASKED);
                mask.setDisplayed(true);
                //添加提示信息
                if (typeof msg == 'string') {
                    var mm = dh.append(dom, {cls : EXTELMASKMSG, cn:{tag:'div'}}, true);
                    data(dom, 'maskMsg', mm);
                    mm.dom.className = msgCls ? EXTELMASKMSG + " " + msgCls : EXTELMASKMSG;
                    mm.dom.firstChild.innerHTML = msg;
                    mm.setDisplayed(true);
                    mm.center(me);
                }
                
                // ie will not expand full height automatically
                //对于ie需重新设置其高度
                if (Ext.isIE && !(Ext.isIE7 && Ext.isStrict) && me.getStyle('height') == 'auto') {
                    mask.setSize(undefined, me.getHeight());
                }
                
                return mask;
            },


            /**
             * 移除之前用过的遮罩
             * Removes a previously applied mask.
             */
            unmask : function() {
                var me      = this,
                    dom     = me.dom,
                    mask    = data(dom, 'mask'),
                    maskMsg = data(dom, 'maskMsg');

                if (mask) {
                    if (maskMsg) {
                        maskMsg.remove();
                        data(dom, 'maskMsg', undefined);
                    }
                    
                    mask.remove();
                    data(dom, 'mask', undefined);
                    me.removeClass([XMASKED, XMASKEDRELATIVE]);
                }
            },

     利用这两个方法可以很方便的给元素加载遮罩效果,如果被遮罩的元素z-index大于100,则只需重新设置遮罩元素的z-index即可,代码中已说明过mask.setStyle('z-index',1000);     另外方法isMasked可以判断Element是否应用了遮罩效果

/**
             * 判断该Element是否应用了遮罩效果
             * Returns true if this element is masked
             * @return {Boolean}
             */
            isMasked : function() {
                var m = data(this.dom, 'mask');
                return m && m.isVisible();
            },

类Ext.LoadMask

      该类封装了上面提到的方法mask和unmask,如果实例化类Ext.LoadMask时,传入的参数中有store对象,则会自动在加载store时处理遮罩层效果,并且加载完后销毁遮罩层,如果不传入则需手动调用show、hide来显示和隐藏遮罩层,代码如下

Ext.LoadMask = function(el, config){
    this.el = Ext.get(el);
    Ext.apply(this, config);
    if(this.store){
        this.store.on({
            scope: this,
            beforeload: this.onBeforeLoad,
            load: this.onLoad,
            exception: this.onLoad
        });
        this.removeMask = Ext.value(this.removeMask, false);
    }else{
        var um = this.el.getUpdater();//获取这个元素的UpdateManager。
        um.showLoadIndicator = false; // disable the default indicator不显示默认的指示器,即提示信息
        um.on({
            scope: this,
            beforeupdate: this.onBeforeLoad,
            update: this.onLoad,
            failure: this.onLoad
        });
        this.removeMask = Ext.value(this.removeMask, true);
    }
};

方法show调用了onBeforeLoad

onBeforeLoad : function(){
        if(!this.disabled){
            this.el.mask(this.msg, this.msgCls);
        }
    },

该方法调用了Element中的方法mask来显示遮罩,而方法hide调用了onLoad

onLoad : function(){
        this.el.unmask(this.removeMask);
    },

该方法调用了Element中的方法unmask来销毁遮罩层

用法,在Ext组件GridPanel中使用了Ext.LoadMask来实现遮罩效果,代码如下

if(this.loadMask){//显示遮罩层
            this.loadMask = new Ext.LoadMask(this.bwrap,
                    Ext.apply({store:this.store}, this.loadMask));
        }

GridPanel中遮罩层显示在this.bwrap上,在使用过程中也可以参考GridPanel的使用

      Ext.LoadMask有个缺点就是不能动态的设置遮罩层的z-index,如果被遮罩的组件或元素z-index设置的太大,则利用该类实现遮罩时,遮罩效果失败。解决问题有两种方法,一种就是直接利用Element.mask和Element.unMask来显示、销毁遮罩,同时设置z-index,mask.setStyle('z-index',1000);这样对于store就不能达到实际的效果,还需动态的书写store加载前、加载后和加载失败的遮罩处理代码,另一种方法就是直接修改或扩展Ext.LoadMask的方法onBeforeLoad来返回遮罩对象(即把this.mask暴露出来,用户可调用),代码如下

onBeforeLoad : function(){
        if(!this.disabled){
            this.mask = this.el.mask(this.msg, this.msgCls);
        }
    },

其实最简单的方法就是,通过以下代码来获取mask对象并且设置z-index

var mask = el.query ('div. ext-el-mask')[0];
//或
//var mask = el. child ('div. ext-el-mask');
mask.setStyle('z-index',1000);

参考例子

var mask = new Ext.LoadMask(Ext.getBody(), {
        removeMask: true,
        msg: '正在加载,请稍等...'
    });
    mask.show();
    //延迟执行
   var task = new Ext.util.DelayedTask(mask.hide, mask);
     task.delay(5000);//5秒后执行

 自定义扩展遮罩层

      除了Ext提供的遮罩层封装类,用户也可以自己扩展定义,如下

this.mask = Ext.DomHelper.append(Ext.getBody(),{cls:'ext-el-mask'},true);
this.mask.enableDisplayMode('block');
this.mask.setSize(Ext.lib.Dom.getViewWidth(true), Ext.lib.Dom.getViewHeight(true));
this.mask.setStyle('z-index', 100000);

      首先创建遮罩层元素,并设置其隐藏方式,然后设置遮罩层高度和宽度,最后修改z-index,在不需要显示遮罩时隐藏或销毁遮罩层,代码如下

this.mask.hide();
Ext.destroy(
   this.mask
);

 如果还想加上遮罩提示信息,则可以加入如下代码

var maskMsg = Ext.DomHelper.append(Ext.getBody(), {
        cls: 'ext-el-mask-msg',
        cn: {
            tag: 'div',
            cls: 'x-mask-loading',
            html: '正在加载,请稍等...'
        }
    }, true);
    maskMsg.setDisplayed(true);
    maskMsg.center(Ext.getBody());

相关推荐