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始终是麻烦的效果。做的时候需要仔细。否则会有各种问题。