`
flyingis
  • 浏览: 292082 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论
阅读更多
    译者: Flyingis

    终于完成了全文的翻译,由于时间比较参促,文章没有过多的校正与润色,阅读过程中难免会有些许生硬或不准确的感觉,请大家见量并指出,方便他人阅读。

    原文作者将拖放功能的实现分步讲解,其核心的地方在于移动和放置元素时,鼠标、移动元素、目标元素关系的处理,只要这个问题处理好了,代码就很容易理解,译文仅供辅助参考之用。

    整合所有的功能

    最后我们使用所有代码片断,来创建一个完整的拖放函数脚本。我们所要做的第一件事情是DOM操作,如果你对此并不十分熟悉,可以阅读《 JavaScript Primer on DOM Manipulation 》。

    接下来的代码创建容器和容器组,使得在这些容器中可以拖动每个元素,这在本文第二个demo的基础上来完成。这段代码能够用来重新规划元素的顺序,将导航窗口放在页面的左侧或右侧,或再加入你所能想到的其他的功能。

    我们将使用伪代码来一步步进行讲解,将真实的代码通过注释的方式留给读者查看。

    1.当文档第一次被加载时,我们创建一个名为dragHelper的DIV标签,当我们开始移动一个元素的时候,dragHelper将成为一个隐藏元素,可以四处移动。真实的元素并不会被拖动,仅仅使用insertBefore和appendChild来移动。我们在开始的时候隐藏dragHelper。

    2.我们创建mouseDown和mouseUp函数。起初,所有的这些函数都假设记录了鼠标按钮的状态,以至于iMouseDown变量在鼠标按下的时候为true,没有按下的时候为false。

    3.我们创建一个全局变量DragDrops,以及一个函数CreateDragContainer。DragDrops包含一组相互关联的容器。传入CreateDragContainer的任何变量(代表容器)被组织成一个新的集合,使元素能够在这些容器间自由移动。通过setAttribute,CreateDragContainer函数同样将各容器中的元素绑定在一起。

    4.现在我们的代码知道每个元素所在的集合,现在来看mouseMove函数。mouseMove函数首先设置了一个变量target,表示鼠标下面的目标元素,如果这个元素在集合(用getAttribute判断)中就继续下面操作:

    4.1.首先,在必要的时候,我们运行一个简单的脚本来改变目标元素的class属性,这样就创造了一个翻动的效果。

    4.2.然后我们检查鼠标是否点击(因为我们的代码已经运行到这里),如果事件发生:

    4.2.1.设置变量curTarget为当前元素。
    4.2.2.记录元素当前在文档中的位置,以便在需要的时候可以将它的值取回。
    4.2.3.将当前元素克隆到dragHelper,使得我们能够移动元素的隐藏备份。
    4.2.4.因为在dragHelper中我们完全拥有了拖动元素的一个备份,这个元素会始终在鼠标下,我们必须移除dragObj属性,让代码知道dragObj已不在集合中。
    4.2.5.我们快速记录集合中每个元素当前的位置、宽度和高度。当元素第一次开始被拖动时,我们仅需做一次这种工作,否则每当鼠标移动的时候我们都必须做一次,甚至一秒内几百次。

    4.3.如果鼠标没有点击,要么我们和之前拥有同样的目标元素,要么没有目标元素,不论哪种情况我们都不会做任何事情。

    5.现在我们检查curTarget变量。curTarget应该仅包含一个被拖动的对象,因此如果它存在,表示我们正在拖动一个元素:

    5.1.移动隐藏DIV到鼠标,这个元素和文章前面所创建的元素一样能够被拖动。

    5.2.然后我们检查鼠标是否存在于当前集合中每个容器中。

    5.2.1.如果鼠标在某个容器中,我们检查容器中的每个元素,查看我们正拖动的元素属于哪个位置。
    5.2.2.然后我们将所拖动的元素放置在容器中另一个元素的前面,或容器的最后位置。
    5.2.3.最后我们确定元素可见。

    6.剩下的事情就是捕获mouseUp事件:
    6.1.首先需要隐藏dragHelper:它不再被需要,因为我们没有拖动任何东西。
    6.2.如果拖动的元素是可见的,它已经存在于任何它所属的容器中,所有工作已完成。
    6.3.如果拖动的元素不可见,我们将它放回它原来所在的地方。
//  iMouseDown represents the current mouse button state: up or down
/**/ /**/ /**/ /*
lMouseState represents the previous mouse button state so that we can
check for button clicks and button releases:

if(iMouseDown && !lMouseState) // button just clicked!
if(!iMouseDown && lMouseState) // button just released!
*/

var  mouseOffset  =   null ;
var  iMouseDown   =   false ;
var  lMouseState  =   false ;
var  dragObject   =   null ;

//  Demo 0 variables
var  DragDrops    =  [];
var  curTarget    =   null ;
var  lastTarget   =   null ;
var  dragHelper   =   null ;
var  tempDiv      =   null ;
var  rootParent   =   null ;
var  rootSibling  =   null ;

Number.prototype.NaN0
= function () { return  isNaN( this ) ? 0 : this ;}

function  CreateDragContainer() {
  
/**/ /**/ /**/ /*
  Create a new "Container Instance" so that items from one "Set" can not
  be dragged into items from another "Set"
  
*/

  
var  cDrag  =  DragDrops.length;
  DragDrops[cDrag] 
=  [];

  
/**/ /**/ /**/ /*
  Each item passed to this function should be a "container".  Store each
  of these items in our current container
  
*/

  
for ( var  i = 0 ; i < arguments.length; i ++ ) {
    
var  cObj  =  arguments[i];
    DragDrops[cDrag].push(cObj);
    cObj.setAttribute('DropObj', cDrag);

    
/**/ /**/ /**/ /*
    Every top level item in these containers should be draggable.  Do this
    by setting the DragObj attribute on each item and then later checking
    this attribute in the mouseMove function
    
*/

    
for ( var  j = 0 ; j < cObj.childNodes.length; j ++ ) {

      
//  Firefox puts in lots of #text nodesskip these
       if (cObj.childNodes[j].nodeName == '#text')  continue ;

      cObj.childNodes[j].setAttribute('DragObj', cDrag);
    }

  }

}


function  mouseMove(ev) {
    ev 
=  ev  ||  window.event;

    
/**/ /**/ /**/ /*
    We are setting target to whatever item the mouse is currently on
    Firefox uses event.target here, MSIE uses event.srcElement
    
*/

    
var  target  =  ev.target  ||  ev.srcElement;
    
var  mousePos  =  mouseCoords(ev);

    
//  mouseOut event - fires if the item the mouse is on has changed
     if (lastTarget  &&  (target !== lastTarget)) {
      
//  reset the classname for the target element
       var  origClass  =  lastTarget.getAttribute('origClass');
      
if (origClass) lastTarget.className  =  origClass;
    }


    
/**/ /**/ /**/ /*
    dragObj is the grouping our item is in (set from the createDragContainer function).
    if the item is not in a grouping we ignore it since it can't be dragged with this
    script.
    
*/

    
var  dragObj  =  target.getAttribute('DragObj');

    
//  if the mouse was moved over an element that is draggable
     if (dragObj != null ) {
      
//  mouseOver event - Change the item's class if necessary
       if (target != lastTarget) {
        
var  oClass  =  target.getAttribute('overClass');
        
if (oClass) {
          target.setAttribute('origClass', target.className);
          target.className 
=  oClass;
        }

      }


      
//  if the user is just starting to drag the element
       if (iMouseDown  &&   ! lMouseState) {
        
//  mouseDown target
        curTarget  =  target;

        
//  Record the mouse x and y offset for the element
        rootParent  =  curTarget.parentNode;
        rootSibling 
=  curTarget.nextSibling;

        mouseOffset   
=  getMouseOffset(target, ev);

        
//  We remove anything that is in our dragHelper DIV so we can put a new item in it.
         for ( var  i = 0 ; i < dragHelper.childNodes.length; i ++ ) dragHelper.removeChild(dragHelper.childNodes[i]);

        
//  Make a copy of the current item and put it in our drag helper.
        dragHelper.appendChild(curTarget.cloneNode( true ));
        dragHelper.style.display 
=  'block';

        
//  set the class on our helper DIV if necessary
         var  dragClass  =  curTarget.getAttribute('dragClass');
        
if (dragClass) {
          dragHelper.firstChild.className 
=  dragClass;
        }


        
//  disable dragging from our helper DIV (it's already being dragged)
        dragHelper.firstChild.removeAttribute('DragObj');

        
/**/ /**/ /**/ /* </sp>
分享到:
评论

相关推荐

    简易而又灵活的Javascript拖拽框架(一)

    js拖拽的时候,发现了一个强大而又灵活的拖拽框架,(之前用了代码混淆器,还好代码比较短,我就翻译过来了)利用这个框架不仅能实现简单的拖动,更能轻易的实现各种复杂的拖放功能。这一篇先实现最简单的拖拽,稍微...

    HTML5精粹:利用HTML5开发令人惊奇的Web站点和革命性应用 pdf扫描版

    第5章详细介绍了HTML5中的音频和视频特性,以及如何在HTML5中创建视频和音频;第6章讲解了HTML5中的各种表单(包含新增表达元素)及其新属性,以及表单API;第7章介绍了Canvas的特性及其使用,以及Canvas的API;第8...

    基于Qt Creator实现中国象棋人机对战, c++实现.zip

    Signal & Slot机制是Qt中实现对象间事件驱动通信的核心方式。信号代表对象状态变化或事件发生,槽则是响应这些信号的可调用实体。这种松耦合的通信方式简化了异步编程和事件处理。 QML与Qt Quick: QML是一种...

    精通qt4编程(源代码)

    \ 第7章 拖放操作与剪贴板 蔡志明 本章简要地说明了基于MIME的拖放操作和剪贴板的使用,关于Graphics View框架的拖放操作也在本章。 212 \ 第8章 文件处理 蔡志明介绍了Qt的文件处理,包括基于流的文本文件和二进制...

    精通Qt4编程(第二版)源代码

    \两年前,当我们准备在Linux系统下开发GUI应用软件时,首先想到的就是选择一个GUI应用框架来简化开发。在三大GUI框架GTK+、Qt和wxWidgets 之间,我们选择了Qt 4工具包。作为重量级桌面系统KDE多年的坚实基础,Qt应该...

    基于QT实现的地图导航系统(Dijkstra算法).zip

    Signal & Slot机制是Qt中实现对象间事件驱动通信的核心方式。信号代表对象状态变化或事件发生,槽则是响应这些信号的可调用实体。这种松耦合的通信方式简化了异步编程和事件处理。 QML与Qt Quick: QML是一种...

    ChineseChess 中国象棋,使用QT基于C++编写,实现了完整的人机对战.zip

    Signal & Slot机制是Qt中实现对象间事件驱动通信的核心方式。信号代表对象状态变化或事件发生,槽则是响应这些信号的可调用实体。这种松耦合的通信方式简化了异步编程和事件处理。 QML与Qt Quick: QML是一种...

    指纹识别算法练习,基于FVC2004数据库,Qt平台开发,核心C语言实现.zip

    Signal & Slot机制是Qt中实现对象间事件驱动通信的核心方式。信号代表对象状态变化或事件发生,槽则是响应这些信号的可调用实体。这种松耦合的通信方式简化了异步编程和事件处理。 QML与Qt Quick: QML是一种...

    基于Qt编写的智能管家系统客户端,实现语音识别,按钮音效,摄像头采集。.zip

    Signal & Slot机制是Qt中实现对象间事件驱动通信的核心方式。信号代表对象状态变化或事件发生,槽则是响应这些信号的可调用实体。这种松耦合的通信方式简化了异步编程和事件处理。 QML与Qt Quick: QML是一种...

    基于Qt的P2P聊天软件实现,主要由多个聊天客户端和一个中心注册服务器组成。.zip

    Signal & Slot机制是Qt中实现对象间事件驱动通信的核心方式。信号代表对象状态变化或事件发生,槽则是响应这些信号的可调用实体。这种松耦合的通信方式简化了异步编程和事件处理。 QML与Qt Quick: QML是一种...

    基于Qt编写的音乐播放器,界面由QML编写,网络和文件由C++实现,能够搜索和播放在线歌曲。.zip

    Signal & Slot机制是Qt中实现对象间事件驱动通信的核心方式。信号代表对象状态变化或事件发生,槽则是响应这些信号的可调用实体。这种松耦合的通信方式简化了异步编程和事件处理。 QML与Qt Quick: QML是一种...

    大名鼎鼎SWFUpload- Flash+JS 上传

     SWFUpload不同于其他基于Flash构建的上传工具,它有着优雅的代码设计,开发者可以利用XHTML、CSS和JavaScript来随心所欲的定制它在浏览器下的外观;它还提供了一组简明的JavaScript事件,借助它们开发者可以方便的...

    JAVA上百实例源码以及开源项目

    像坐标控制、旋转矩阵、定时器、生成图像、数据初始化、矩阵乘法、坐标旋转、判断是否是顺时针方向排列、鼠标按下、放开时的动作等,都可在本源码中得以体现。 Java编写的显示器显示模式检测程序 2个目标文件 内容...

    JAVA上百实例源码以及开源项目源代码

    像坐标控制、旋转矩阵、定时器、生成图像、数据初始化、矩阵乘法、坐标旋转、判断是否是顺时针方向排列、鼠标按下、放开时的动作等,都可在本源码中得以体现。 Java编写的显示器显示模式检测程序 2个目标文件 内容...

    嵌入式设备基于liunx下的一个QT程序,KTV点歌系统.zip

    Signal & Slot机制是Qt中实现对象间事件驱动通信的核心方式。信号代表对象状态变化或事件发生,槽则是响应这些信号的可调用实体。这种松耦合的通信方式简化了异步编程和事件处理。 QML与Qt Quick: QML是一种...

    基于Qt的不围棋(nogo)单机对战平台,包含基于MCTS的AI对战Bot.zip

    Signal & Slot机制是Qt中实现对象间事件驱动通信的核心方式。信号代表对象状态变化或事件发生,槽则是响应这些信号的可调用实体。这种松耦合的通信方式简化了异步编程和事件处理。 QML与Qt Quick: QML是一种...

    基于Qt QGraphicsView的简易画图软件.zip

    Signal & Slot机制是Qt中实现对象间事件驱动通信的核心方式。信号代表对象状态变化或事件发生,槽则是响应这些信号的可调用实体。这种松耦合的通信方式简化了异步编程和事件处理。 QML与Qt Quick: QML是一种...

    基于CTP和Qt的可视化期货监控系统.zip

    Signal & Slot机制是Qt中实现对象间事件驱动通信的核心方式。信号代表对象状态变化或事件发生,槽则是响应这些信号的可调用实体。这种松耦合的通信方式简化了异步编程和事件处理。 QML与Qt Quick: QML是一种...

    基于qt编写的五子棋和围棋游戏.zip

    Signal & Slot机制是Qt中实现对象间事件驱动通信的核心方式。信号代表对象状态变化或事件发生,槽则是响应这些信号的可调用实体。这种松耦合的通信方式简化了异步编程和事件处理。 QML与Qt Quick: QML是一种...

Global site tag (gtag.js) - Google Analytics