[转帖]Mootools源码分析-44 -- Sortables

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

原作者:我佛山人

 

ContractedBlock.gif ExpandedBlockStart.gif 代码
// 拖放排序类
//
演示:http://demos.mootools.net/Sortables
var  Sortables  =   new  Class({

    
// 继承自Events和Options,UI插件的特点
    Implements: [Events, Options],

    options: {
/*
        //排序事件
        onSort: $empty,
        //开始事件
        onStart: $empty,
        //完成事件
        onComplete: $empty,
*/
        snap: 
4 ,
        
// 透明度
        opacity:  1 ,
        
// 是否复制
        clone:  false ,
        
// 是否使用形变动画
        revert:  false ,
        
// 拖动句柄对象
        handle:  false ,
        
// 约束
        constrain:  false
    },

    
// 构造函数
    initialize:  function (lists, options)    {
        
// 设置配置参数
         this .setOptions(options);
        
this .elements  =  [];
        
this .lists  =  [];
        
this .idle  =   true ;

        
// 列表项可以单个,也可以是符合
         this .addLists($$($(lists)  ||  lists));
        
// 如果不克隆副本,则不需要变形动画
         if  ( ! this .options.clone)     this .options.revert  =   false ;
        
// 如果指定变形动画效果
         if  ( this .options.revert)  this .effect  =   new  Fx.Morph( null , $merge({duration:  250 , link:  ' cancel ' },  this .options.revert));
    },

    
// 附加事件
    attach:  function ()    {
        
this .addLists( this .lists);
        
return   this ;
    },

    
// 移除事件
    detach:  function ()    {
        
this .lists  =   this .removeLists( this .lists);
        
return   this ;
    },

    
// 添加列表项
    addItems:  function ()    {
        
// 给参数降维再遍历
        Array.flatten(arguments).each( function (element)    {
            
// 加到数组
             this .elements.push(element);
            
// 将关联本列表项的start方法缓存
             var  start  =  element.retrieve( ' sortables:start ' this .start.bindWithEvent( this , element));

            
// 如果指定拖动句柄,从当前列表项中获取,否则将当前列表项作为句柄
             // 然后给句柄添加鼠标按下事件,触发start方法
            ( this .options.handle  ?  element.getElement( this .options.handle)  ||  element : element).addEvent( ' mousedown ' , start);
        }, 
this );
    
return   this ;
    },

    
// 添加列表
    addLists:  function ()    {
        
// 给参数降维再遍历
        Array.flatten(arguments).each( function (list)    {
            
this .lists.push(list);
            
// 添加当前列表下的项
             this .addItems(list.getChildren());
        }, 
this );
        
return   this ;
    },

    
// 移除列表项
    removeItems:  function ()    {
        
// 用于返回的数组
         var  elements  =  [];
        
// 给参数降维再遍历
        Array.flatten(arguments).each( function (element)    {
            
// 加到返回数组
            elements.push(element);
            
// 从数组中删除
             this .elements.erase(element);
            
// 取缓存中的事件绑定方法
             var  start  =  element.retrieve( ' sortables:start ' );
            
// 类似添加列表项时的判断,找到句柄后移除事件
            ( this .options.handle  ?  element.getElement( this .options.handle)  ||  element : element).removeEvent( ' mousedown ' , start);
        }, 
this );
        
// 返回移除的列表项集合
         return  $$(elements);
    },

    
// 移除列表
    removeLists:  function ()    {
        
// 用于返回的数组
         var  lists  =  [];
        
// 给参数降维再遍历
        Array.flatten(arguments).each( function (list)    {
            
// 加到返回数组
            lists.push(list);
            
// 从数组中删除
             this .lists.erase(list);
            
// 移除当前列表的所有列表项,因为removeItems方法中自动给参数降维,所以可以直接传数组
             this .removeItems(list.getChildren());
        }, 
this );
        
// 返回移除的列表集合
         return  $$(lists);
    },

    
// 获取复制的对象
    getClone:  function (event, element)    {
        
// 如果指定不复制,返回新创建的div并插入到body
         if  ( ! this .options.clone)     return   new  Element( ' div ' ).inject(document.body);
        
// 如果参数为函数,修改其调用的上下文指向并传送指定参数
         if  ($type( this .options.clone)  ==   ' function ' )     return   this .options.clone.call( this , event, element,  this .list);
        
// 剩下的是指定为复制的情况
         // 复制当前列表项并修改其样式
         return  element.clone( true ).setStyles({
                
' margin ' ' 0px ' ,
                
' position ' ' absolute ' ,
                
' visibility ' ' hidden ' ,
                
' width ' : element.getStyle( ' width ' )
        }).inject(
this .list).position(element.getPosition(element.offsetParent));
    },

    
// 获取可放落的对象
    getDroppables:  function ()    {
        
// 取当前列表下的所有列表项
         var  droppables  =   this .list.getChildren();
        
// 如果没有约束,则其它列表也作为可放落对象
         if  ( ! this .options.constrain)    droppables  =   this .lists.concat(droppables).erase( this .list);
        
// 从可放落对象集合中排除当前对象及其克隆
         return  droppables.erase( this .clone).erase( this .element);
    },

    
// 插入
    insert:  function (dragging, element)    {
        
// 指定插入位置
         var  where  =   ' inside ' ;
        
if  ( this .lists.contains(element))    {
            
this .list  =  element;
            
this .drag.droppables  =   this .getDroppables();
        }    
else     {
            where 
=   this .element.getAllPrevious().contains(element)  ?   ' before '  :  ' after ' ;
        }
        
this .element.inject(element, where);
        
this .fireEvent( ' onSort ' , [ this .element,  this .clone]);
    },

    
// 开始操作
    start:  function (event, element)    {
        
// 如果当前非闲置状态,退出
         if  ( ! this .idle)     return ;
        
// 设置闲置状态标识
         this .idle  =   false ;
        
// 当前操作对象
         this .element  =  element;
        
// 获取当前透明度
         this .opacity  =  element.get( ' opacity ' );
        
// 获取当前操作对象所在的列表对象
         this .list  =  element.getParent();
        
// 获取当前操作对象的克隆对象
         this .clone  =   this .getClone(event, element);

        
// 创建拖放对象
         this .drag  =   new  Drag.Move( this .clone, {
            snap: 
this .options.snap,
            
// 拖放范围,如果指定constrain参数为true才会取当前对象所在的列表对象
            container:  this .options.constrain  &&   this .element.getParent(),
            
// 获取可放落的对象
            droppables:  this .getDroppables(),
            
// onSnap事件监听
            onSnap:  function ()    {
                
// 停止事件冒泡及返回值
                event.stop();
                
// 显示克隆对象
                 this .clone.setStyle( ' visibility ' ' visible ' );
                
// 设置透明度
                 this .element.set( ' opacity ' this .options.opacity  ||   0 );
                
// 触发onStart事件
                 this .fireEvent( ' onStart ' , [ this .element,  this .clone]);
            }.bind(
this ),
            
// 拖动进入事件
            onEnter:  this .insert.bind( this ),
            
// 取消拖动事件
            onCancel:  this .reset.bind( this ),
            
// 拖动完成事件
            onComplete:  this .end.bind( this )
        });
        
// 插入克隆对象到当前对象前面
         this .clone.inject( this .element,  ' before ' );
        
// 开始拖动
         this .drag.start(event);
    },

    
// 结束拖动排序
    end:  function ()    {
        
// 移除事件
         this .drag.detach();
        
// 恢复透明度
         this .element.set( ' opacity ' this .opacity);
        
// 如果使用形变动画(主要是外形尺寸和坐标位置上的)
         if  ( this .effect)    {
            
// 获取尺寸
             var  dim  =   this .element.getStyles( ' width ' ' height ' );
            
// 计算位置
             var  pos  =   this .clone.computePosition( this .element.getPosition( this .clone.offsetParent));
            
// 将当前克隆对象作为形变对象
             this .effect.element  =   this .clone;
            
// 开始动画效果
             this .effect.start({
                top: pos.top,
                left: pos.left,
                width: dim.width,
                height: dim.height,
                opacity: 
0.25
                
// 动画完成后的后续操作
            }).chain( this .reset.bind( this ));
        }    
else     {
            
// 后续操作
             this .reset();
        }
    },

    
// 重置
    reset:  function ()    {
        
// 设置闲置状态标记
         this .idle  =   true ;
        
// 清除克隆对象
         this .clone.destroy();
        
// 触发onComplete事件
         this .fireEvent( ' onComplete ' this .element);
    },

    
// 序列化
    serialize:  function ()    {
        
// 使用Array.link处理参数
         var  params  =  Array.link(arguments, {modifier: Function.type, index: $defined});
        
// 遍历列表集
         var  serial  =   this .lists.map( function (list)    {
            
// 遍历各列表的列表项,如果参数中传有函数的引用,使用该函数处理列表项,否则默认返回id
             return  list.getChildren().map(params.modifier  ||   function (element)    {
                
// 取列表项的id
                 return  element.get( ' id ' );
            }, 
this );
        }, 
this );

        
// 参数中传送的索引值
         var  index  =  params.index;
        
// 如果列表集中只有一项,则索引值为0
         if  ( this .lists.length  ==   1 ) index  =   0 ;
        
// 如果索引存在并且值在合法范围内,返回指定索引值列表的序列化结果,否则返回整个列表集的序列化结果
         return  $chk(index)  &&  index  >=   0   &&  index  <   this .lists.length  ?  serial[index] : serial;
    }
});

 

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值