博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

(十一)模仿Ext的 Resizer 和 Drag 的窗口。

Posted on 2011-02-15 22:56  xuld  阅读(585)  评论(0编辑  收藏  举报

Ext的 Resize 和 Drag 界面非常漂亮,很多朋友想把它用到自己的地方,却不想用整个Ext ,所以本文特别对这2个效果进行制作。让我们先看下效果:

1. 修正一些认识。

     很多朋友肯能认为拖动时的虚线和透明窗口是为了美观,但其实它们更为了效率。如果窗口里有很多元素,如果经常改变大小,会导致内部元素经常重新布局,最后导致效果卡得不能用。

2. 复习上文的拖动。

    上文介绍了如何实现拖动,最终我们可以通过如下代码实现拖动:

     elem.on('dragstart', function(){});

3. resizer 节点。

   resize时见到的虚框其实是一个和窗口没关的div,我们把这个div称为代理层。 (div-proxy)

当鼠标按下角落时 - 显示代理,并附在窗口上 - 当鼠标移动, 改变代理大小。 - 当鼠标放开 - 隐藏代码, 设置窗口大小。

4. 拖动句柄。

   所谓的句柄就是八个可触发resize的小东西,这些东西可用<div>实现:

            <div class="x-resizable-lt">
            </div>
            <div class="x-resizable-t">
            </div>
            <div class="x-resizable-rt">
            </div>
            <div class="x-resizable-l">
            </div>
            <div class="x-resizable-r">
            </div>
            <div class="x-resizable-lb">
            </div>
            <div class="x-resizable-b">
            </div>
            <div class="x-resizable-rb">
            </div>

每个滑块:

.x-resizable-lt, .x-resizable-t, .x-resizable-rt, .x-resizable-l, .x-resizable-r, .x-resizable-lb, .x-resizable-b, .x-resizable-rb {
	overflow: hidden;
	width: 6px;
	height: 6px;
	position: absolute;
}

.x-resizable-lt {
	top: 0;
	left: 0;
	z-index: 2;
	cursor: nw-resize;
}

.x-resizable-t {
	width: 100%;
	top: 0;
	left: 0;
	z-index: 1;
	cursor: n-resize;
}

.x-resizable-rt {
	top: 0;
	right: 0;
	cursor: ne-resize;
}

.x-resizable-l {
	left: 0;
	cursor: w-resize;
}

.x-resizable-r {
	right: 0;
	cursor: e-resize;
}

.x-resizable-lb {
	bottom: 0;
	left: 0;
	z-index: 2;
	cursor: sw-resize;
}

.x-resizable-b {
	width: 100%;
	bottom: 0;
	left: 0;
	cursor: s-resize;
}

.x-resizable-rb {
	bottom: 0;
	right: 0;
	cursor: se-resize;
} 

这样,便可见到这些句柄。

原理不多说了,看代码就知道。

5. 绑定事件-开始拖动

以右滑块例,

document.queryOne('.x-resizable-r').on('dragstart', function(e){

  showProxy();  // 显示代理

}

document.queryOne('.x-resizable-r').on('dragmove', function(e){

 resize();  // 更改代理的大小

});

document.queryOne('.x-resizable-r').on('dragend', function(e){

 hideProxy();  // 显示代理

});
function showProxy(){
    $('proxy').show(); // 显示代理
    $('proxy').setBound(  $('elem').getBound() );  // 更改位置和大小 (具体实现见本系列(五))
}

function resize(e){   

   resizeEl(e, $('proxy');   // 根据e修改大小。
}


function hideProxy(e){
    $('proxy').hide(); // 显示代理

     resizeEl(e, $('elem'));  
   
}


function resizeEl(e, tg){     // 根据e修改大小。
   
    tg.resizeBy(  e.delta );   
  
    if({'x-resizable-l':1, 'x-resizable-t':1}[e.target.className]) {   // 如果是左上方向,需同时移动偏移位置。
       tg.moveBy( e.delta.plus(-1) );  // 移动的方向和大小改变的是相反。
    }
}

  6. 以上是对 left - top - bottom - right 实现,那角落如何处理(以右下角例)。

     其实在上面已经藏着玄机。 当鼠标按下右下角的滑块,其实也按了右滑块,下滑块。所以,把右下角的滑块事件转为右滑块,下滑块的结合(同时进行)

     这是 Ext未使用的方法, 有个优点,就是节约代码。

    所以上面的代码已经实现了每个角落的事件。

最后说个细节:

鼠标在拖到时,希望保持箭头方向,但除部分浏览器,其它浏览器会随文本更新鼠标样式。

最简单是方法为 设置 document.body.setStyle('cursor', 'resizer-x')

但这时 Chrome 仍然按因 select 更改鼠标 。

Ext 采用 layer 式处理, 即 在拖到前,全局加上 layer(透明,全局) 全部拖动都在 layer 上触发,这样兼容任何浏览器。

resize始终是麻烦的效果。做的时候需要仔细。否则会有各种问题。