[翻译] 如何在 JavaScript 中实现拖放(中)

    译者: Flyingis 

    上一篇文章 介绍了移动页面元素所涉及到的捕获鼠标移动和鼠标点击的相关问题,本段文章将介绍如何移动和放置页面元素。

    移动元素

    我们现在已经知道如何捕获鼠标移动和点击。接下来需要做的就是移动任何我们想拖动的元素。首先,将一个元素准确移动到页面上我们想要的位置,该元素样式表的position值必须为absolute,这意味着你可以设置它的style.top或style.left,测量值相对于页面的左上角,因为我们所有的鼠标移动都是相对于页面左上角的,通常都是这样。

    一旦我们设置了item.style.position='absolute',接下来就需要改变该元素top和left的位置,使它移动!

None.gifdocument.onmousemove  =  mouseMove;
None.gifdocument.onmouseup   
=
 mouseUp;
None.gif
None.gif
var  dragObject   =   null
;
None.gif
var  mouseOffset  =   null
;
None.gif
ExpandedBlockStart.gifContractedBlock.gif
function  getMouseOffset(target, ev)  dot.gif
{
InBlock.gif  ev 
=  ev  ||
 window.event;
InBlock.gif
InBlock.gif  
var  docPos  =
 getPosition(target);
InBlock.gif  
var  mousePos  =
 mouseCoords(ev);
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif   
return   dot.gif {x:mousePos.x  -  docPos.x, y:mousePos.y  -  docPos.y}
;
ExpandedBlockEnd.gif}

None.gif
ExpandedBlockStart.gifContractedBlock.gif
function  getPosition(e)  dot.gif {
InBlock.gif  
var  left  =   0
;
InBlock.gif  
var  top   =   0
;
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif  
while  (e.offsetParent) dot.gif
{
InBlock.gif    left 
+=
 e.offsetLeft;
InBlock.gif    top 
+=
 e.offsetTop;
InBlock.gif    e 
=
 e.offsetParent;
ExpandedSubBlockEnd.gif  }

InBlock.gif
InBlock.gif  left 
+=  e.offsetLeft;
InBlock.gif  top 
+=
 e.offsetTop;
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif  
return   dot.gif {x:left, y:top}
;
ExpandedBlockEnd.gif}

None.gif
ExpandedBlockStart.gifContractedBlock.gif
function  mouseMove(ev)  dot.gif {
InBlock.gif  ev 
=  ev  ||
 window.event;
InBlock.gif  
var  mousePos  =
 mouseCoords(ev);
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif  
if  (dragObject)  dot.gif
{
InBlock.gif    dragObject.style.position 
=
 'absolute';
InBlock.gif    dragObject.style.top 
=  mousePos.y  -
 mouseOffset.y;
InBlock.gif    dragObject.style.left 
=  mousePos.x  -
 mouseOffset.x;
InBlock.gif    
return   false
;
ExpandedSubBlockEnd.gif  }

ExpandedBlockEnd.gif}

None.gif
ExpandedBlockStart.gifContractedBlock.gif
function  mouseUp()  dot.gif {
InBlock.gif  dragObject 
=   null
;
ExpandedBlockEnd.gif}

None.gif
ExpandedBlockStart.gifContractedBlock.gif
function  makeDraggable(item)  dot.gif {
InBlock.gif  
if  ( ! item)  return
;
ExpandedSubBlockStart.gifContractedSubBlock.gif  item.onmousedown 
=   function (ev)  dot.gif
{
InBlock.gif    dragObject  
=   this
;
InBlock.gif    mouseOffset 
=  getMouseOffset( this
, ev);
InBlock.gif    
return   false
;
ExpandedSubBlockEnd.gif  }

ExpandedBlockEnd.gif}

    你会注意到这些代码是以我们前面的例子为基础的(参考上篇文章),将它们放置在一起,你将能够随意的去移动元素。

    当我们点击一个元素时,存储了另外的一个变量,mouseOffset。mouseOffset简单的包含了我们点击元素的位置信息。如果我们有一张20*20px的图像,然后点击图像的中间,mouseOffset应该是{x:10, y:10}。如果我们点击图像的左上角,mouseOffset应为{x:0, y:0}。我们在鼠标移动后的位置信息中用到它。如果我们没有存储这个值,不论你点击元素的哪一个位置,元素相对于鼠标的位置都将会是相同的。

    mouseOffset函数用到了另外一个函数getPosition。getPosition目的是返回元素相对于documemt文档的坐标位置。如果我们简单的去读取item.offsetLeft或item.style.left,得到的将是元素相对于它父元素的位置,而不是document文档的。在我们的脚本中,所有的元素都是相对于document文档的,因此需要这样做。

    要完成获取元素相对于document文档位置的工作,getPosition从它自身的父级开始,循环获取它的left和top的值并累加,这样我们就得到了我们想要的元素距文档顶部和左侧的累计值。

    当我们获取了这条信息并移动鼠标的时候,mouseMove开始运行。首先我们需要保证item.style.position值为absolute,接着,我们将元素移动到任何一个地方,鼠标位置都会减去我们之前记录的鼠标相对于元素的偏移量。当鼠标释放时,dragObject将被设置为null,并且mouseMove函数不再做任何事情。

    放置元素

    我们前面的例子已经处理了这个问题,仅仅是拖动一个元素,然后将它放下。然后,在我们放下元素的时候通常还有其他的目的,我们以拖动元素到垃圾回收站为例,或我们可能想让该元素和页面中某个特定的区域对齐。

    不幸的是我们在这里进入了一个相对主要的问题。因为我们正在移动的元素总是直接处于我们的鼠标下,而不可能去引发mouseover、mousedown、mouseup或鼠标对页面中其他元素的操作。如果你移动一个元素到垃圾回收站,你的鼠标会一直在移动元素的上方,而不是垃圾回收站。

    那么我们该如何处理这个问题呢?这里有几种解决方案。在前面所提到的mouseOffset的目的是保证元素总是在鼠标下方正确的位置,如果你忽视了这点,然后总是使得元素在鼠标的右下方,你的鼠标将不会被你正在拖动的元素所隐藏,我们也不会碰到问题。但事实上往往不会这样,为了美观我们通常要保持元素在鼠标的下方。

    另外一种选择是不移动你正在拖动的元素,你可以改变鼠标样式,来告诉使用者你正在拖动一个元素,直到你将它放置到某个地方。这解决了我们的问题,但是带来了和前面一种方案面临的同样问题:美观。

    我们最后的一种解决方案既不影响你正在移动的元素,也不影响移动终点位置上的元素(例如垃圾回收站)。不幸的是,这比前面两种解决方案的难度更大。我们将要做的是获得一组我们要放置的目标,当鼠标释放时,我们手工检查当前鼠标相对于每个目标的位置,看鼠标是否释放在这个目标中某一个目标的位置上,如果是的,我们就知道我们已经将元素放置在我们的目标上了。

ExpandedBlockStart.gifContractedBlock.gif/**/ /*
InBlock.gifAll code from the previous example is needed with the exception
InBlock.gifof the mouseUp function which is replaced below
ExpandedBlockEnd.gif
*/

None.gif
None.gif
var  dropTargets  =  [];
None.gif
ExpandedBlockStart.gifContractedBlock.gif
function  addDropTarget(dropTarget)  dot.gif
{
InBlock.gif  dropTargets.push(dropTarget);
ExpandedBlockEnd.gif}

None.gif
ExpandedBlockStart.gifContractedBlock.gif
function  mouseUp(ev)  dot.gif {
InBlock.gif  ev 
=  ev  ||
 window.event;
InBlock.gif  
var  mousePos  =
 mouseCoords(ev);
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif  
for  ( var  i = 0 ; i < dropTargets.length; i ++ dot.gif
{
InBlock.gif    
var  curTarget  =
 dropTargets[i];
InBlock.gif    
var  targPos  =
 getPosition(curTarget);
InBlock.gif    
var  targWidth  =
 parseInt(curTarget.offsetWidth);
InBlock.gif    
var  targHeight  =
 parseInt(curTarget.offsetHeight);
InBlock.gif
InBlock.gif    
if
 (
InBlock.gif      (mousePos.x 
>  targPos.x)  &&
 
InBlock.gif      (mousePos.x 
<  (targPos.x  +  targWidth))  &&
 
InBlock.gif      (mousePos.y 
>  targPos.y)  &&
 
ExpandedSubBlockStart.gifContractedSubBlock.gif      (mousePos.y 
<  (targPos.y  +  targHeight)))  dot.gif
{
InBlock.gif      
//  dragObject was dropped onto curTarget!

ExpandedSubBlockEnd.gif
      }

ExpandedSubBlockEnd.gif  }

InBlock.gif
InBlock.gif  dragObject   
=   null ;
ExpandedBlockEnd.gif}

    这个例子中当鼠标释放时,我们循环每个可能放置元素的目标,如果鼠标指针在目标上,我们则拥有了一个放置元素的事件,通过鼠标横坐标大于目标元素左侧横坐标(mousePos.x>targPos.x),小于目标元素右侧横坐标(mousePos.x<(targPos.x+targWidth))来判定,对于Y坐标我们做同样的判断。如果所有的这些值都返回true,那么我们的鼠标就是在目标元素的范围内。

    原文链接:http://www.webreference.com/programming/javascript/mk/column2/2.html

    另外两篇:[翻译] 如何在 JavaScript 中实现拖放(上)   [翻译] 如何在 JavaScript 中实现拖放(下)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
资源包主要包含以下内容: ASP项目源码:每个资源包都包含完整的ASP项目源码,这些源码采用了经典的ASP技术开发,结构清晰、注释详细,帮助用户轻松理解整个项目的逻辑和实现方式。通过这些源码,用户可以学习到ASP的基本语法、服务器端脚本编写方法、数据库操作、用户权限管理等关键技术。 数据库设计文件:为了方便用户更好地理解系统的后台逻辑,每个项目都附带了完整的数据库设计文件。这些文件通常包括数据库结构图、数据表设计文档,以及示例数据SQL脚本。用户可以通过这些文件快速搭建项目所需的数据库环境,并了解各个数据表之间的关系和作用。 详细的开发文档:每个资源包都附有详细的开发文档,文档内容包括项目背景介绍、功能模块说明、系统流程图、用户界面设计以及关键代码解析等。这些文档为用户提供了深入的学习材料,使得即便是从零开始的开发者也能逐步掌握项目开发的全过程。 项目演示与使用指南:为帮助用户更好地理解和使用这些ASP项目,每个资源包都包含项目的演示文件和使用指南。演示文件通常以视频或图文形式展示项目的主要功能和操作流程,使用指南则详细说明了如何配置开发环境、部署项目以及常见问题的解决方法。 毕业设计参考:对于正在准备毕业设计的学生来说,这些资源包是绝佳的参考材料。每个项目不仅功能完善、结构清晰,还符合常见的毕业设计要求和标准。通过这些项目,学生可以学习到如何从零开始构建一个完整的Web系统,并积累丰富的项目经验。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值