[转帖]Mootools源码分析-39 -- Drag

原帖地址:http://space.flash8.net/space/?uid-18713-action-viewspace-itemid-408445

原作者:我佛山人

 

ContractedBlock.gif ExpandedBlockStart.gif 代码
// UI插件,拖动/缩放基类
var  Drag  =   new  Class({
    
// 继承自Events和Options,UI组件的基本要求:事件支持及属性可选
    Implements: [Events, Options],

    options: {
/*
        //开始拖动前事件
        onBeforeStart: $empty,
        //开始拖动事件
        onStart: $empty,
        //拖动事件
        onDrag: $empty,
        //取消拖动事件
        onCancel: $empty,
        //拖动完成事件
        onComplete: $empty,
*/
        
// 自动吸附距离
        snap:  6 ,
        
// 单位
        unit:  ' px ' ,
        
// 网格大小
        grid:  false ,
        
// 指定是否CSS属性
        style:  true ,
        
// 拖动范围限制
        limit:  false ,
        
// 可拖动的句柄
        handle:  false ,
        
// 反转
        invert:  false ,
        
// 鼠标拖动时对象改变的样式属性,当x,y为left和top时是移动,为width和height时为缩放
        modifiers: {x:  ' left ' , y:  ' top ' }
    },

    
// 构造函数
    initialize:  function ()    {
        
// Array.link对参数处理,实现配置属性与作用对象的位置无关性
         var  params  =  Array.link(arguments, { ' options ' : Object.type,  ' element ' : $defined});
        
// 拖动作用的对象
         this .element  =  $(params.element);
        
// 拖动作用对象所属的文档对象
         this .document  =   this .element.getDocument();
        
// 调用Options类的方法,实现可选参数
         this .setOptions(params.options  ||  {});
        
// 句柄参数的类型
         var  htype  =  $type( this .options.handle);
        
// 触发拖动的句柄,可支持多个对象,也可为单个,当不提供handle参数时使用拖动作用的对象
         this .handles  =  (htype  ==   ' array '   ||  htype  ==   ' collection ' ?  $$( this .options.handle) : $( this .options.handle)  ||   this .element;
        
// 鼠标的相关值集合
         this .mouse  =  { ' now ' : {},  ' pos ' : {}};
        
// 对象的坐标值集合
         this .value  =  { ' start ' : {},  ' now ' : {}};
        
// 选取事件名,ie内核浏览器使用onselectstart
         this .selection  =  (Browser.Engine.trident)  ?   ' selectstart '  :  ' mousedown ' ;

        
// 使用闭包绑定当前对象的事件方法集
         this .bound  =  {
            
// 开始
            start:  this .start.bind( this ),
            
// 检查
            check:  this .check.bind( this ),
            
// 拖动
            drag:  this .drag.bind( this ),
            
// 拖动
            stop:  this .stop.bind( this ),
            
// 取消
            cancel:  this .cancel.bind( this ),
            
// 停止事件冒泡,使用$lambda快速构造出functon(){return false;}这样的函数
            eventStop: $lambda( false )
        };
        
// 附加事件
         this .attach();
    },

    
// 附加事件
    attach:  function ()    {
        
this .handles.addEvent( ' mousedown ' this .bound.start);
        
return   this ;
    },

    
// 移除事件
    detach:  function ()    {
        
// 为句柄对象移除鼠标按下事件,之所以要提前绑定并保存方法,是为了事件的可移除性
         // 如果addevent和removeEvent中都使用this.start.bind(this),移除事件将失败
         this .handles.removeEvent( ' mousedown ' this .bound.start);
        
return   this ;
    },

    
// 开始拖动处理
    start:  function (event)    {
        
// 触发拖动前事件
         this .fireEvent( ' onBeforeStart ' this .element);
        
// 鼠标的初始位置信息
         this .mouse.start  =  event.page;
        
// 范围限制
         var  limit  =   this .options.limit;
        
this .limit  =  { ' x ' : [],  ' y ' : []};
        
// 遍历作用的属性名
         for  ( var  z  in   this .options.modifiers)    {
            
// 如果值为false,忽略
             if  ( ! this .options.modifiers[z])     continue ;
            
// 如果指定使用样式属性,从样式中取对应属性值
             if  ( this .options.style)     this .value.now[z]  =   this .element.getStyle( this .options.modifiers[z]).toInt();
            
// 否则从属性中取值
             else      this .value.now[z]  =   this .element[ this .options.modifiers[z]];
            
// 如果指定反转,取负值(正取负,负取正)
             if  ( this .options.invert)     this .value.now[z]  *=   - 1 ;
            
// 计算鼠标相对位置
             this .mouse.pos[z]  =  event.page[z]  -   this .value.now[z];
            
// 如果指定相应方向上的范围限制
             if  (limit  &&  limit[z])    {
                
// 因为范围的限制是一个两项的数组,指定上限及下限,所以循环2次(为什么不直接用(2).times?)
                 for  ( var  i  =   2 ; i -- ; i)    {
                    
// 如果有定义,取值,因为是每次重新求值,并且使用了$lambda,所以可以使用函数返回值
                     // 比如limit :{x : false, y : [function(){return 1}, function(){return 10}]}
                     // 当然,你的函数里可以做更复杂的处理
                     if  ($chk(limit[z][i]))     this .limit[z][i]  =  $lambda(limit[z][i])();
                }
            }
        }
        
// 网格方式的移动/缩放
         if  ($type( this .options.grid)  ==   ' number ' )     this .options.grid  =  { ' x ' this .options.grid,  ' y ' this .options.grid};
        
// 监听当前文档的鼠标移动和弹起事件
         this .document.addEvents({mousemove:  this .bound.check, mouseup:  this .bound.cancel});
        
// 屏蔽当前文档的选择
         this .document.addEvent( this .selection,  this .bound.eventStop);
    },

    
// 检查条件约束
    check:  function (event)    {
        
// 计算当前鼠标移动的距离
         var  distance  =  Math.round(Math.sqrt(Math.pow(event.page.x  -   this .mouse.start.x,  2 +  Math.pow(event.page.y  -   this .mouse.start.y,  2 )));
        
// 如果超出吸附距离
         if  (distance  >   this .options.snap)    {
            
// 移除拖动前检查约束的事件监听
             this .cancel();
            
// 添加拖动处理相关的事件监听
             this .document.addEvents({
                mousemove: 
this .bound.drag,
                mouseup: 
this .bound.stop
            });
            
// 触发onStart和onSnap事件
             this .fireEvent( ' onStart ' this .element).fireEvent( ' onSnap ' this .element);
        }
    },

    
// 拖动
    drag:  function (event)    {
        
// 当前鼠标坐标
         this .mouse.now  =  event.page;
        
// 遍历拖动作用的属性
         for  ( var  z  in   this .options.modifiers)    {
            
// 如果值为false,忽略该属性
             if  ( ! this .options.modifiers[z])     continue ;
            
// 计算当前值
             this .value.now[z]  =   this .mouse.now[z]  -   this .mouse.pos[z];
            
// 反转值
             if  ( this .options.invert)     this .value.now[z]  *=   - 1 ;
            
// 范围限制处理
             if  ( this .options.limit  &&   this .limit[z])    {
                
// 如果当前方向上的值大于上限
                 if  ($chk( this .limit[z][ 1 ])  &&  ( this .value.now[z]  >   this .limit[z][ 1 ]))    {
                    
// 取上限值
                     this .value.now[z]  =   this .limit[z][ 1 ];
                    
// 如果当前值小于下限
                }     else      if  ($chk( this .limit[z][ 0 ])  &&  ( this .value.now[z]  <   this .limit[z][ 0 ]))    {
                    
// 取下限值
                     this .value.now[z]  =   this .limit[z][ 0 ];
                }
            }
            
// 相对于网格大小取值
             if  ( this .options.grid[z])  this .value.now[z]  -=  ( this .value.now[z]  %   this .options.grid[z]);
            
// 根据指定样式还是属性的值设置
             if  ( this .options.style)     this .element.setStyle( this .options.modifiers[z],  this .value.now[z]  +   this .options.unit);
            
else      this .element[ this .options.modifiers[z]]  =   this .value.now[z];
        }
        
// 触发onDrag事件
         this .fireEvent( ' onDrag ' this .element);
    },

    
// 取消
    cancel:  function (event)    {
        
// 移除事件监听
         this .document.removeEvent( ' mousemove ' this .bound.check);
        
this .document.removeEvent( ' mouseup ' this .bound.cancel);
        
if  (event)    {
            
this .document.removeEvent( this .selection,  this .bound.eventStop);
            
// 触发onCancel事件
             this .fireEvent( ' onCancel ' this .element);
        }
    },

    
// 停止,打扫战场
    stop:  function (event)    {
        
// 移除各事件
         this .document.removeEvent( this .selection,  this .bound.eventStop);
        
this .document.removeEvent( ' mousemove ' this .bound.drag);
        
this .document.removeEvent( ' mouseup ' this .bound.stop);
        
// 触发onComplete事件
         if  (event)  this .fireEvent( ' onComplete ' this .element);
    }

});

// 根据Drag为Element扩展功能
Element.implement({
    
// 使当前对象可缩放
    makeResizable:  function (options)    {
        
return   new  Drag( this , $merge({modifiers: { ' x ' ' width ' ' y ' ' height ' }}, options));
    }
});

 

转载于:https://www.cnblogs.com/maapaa/articles/mootools-s-39.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值