• 怎么用javascript进行拖拽


    Javascript的特点是dom的处理与网页效果,大多数情况我们只用到了这个语言的最简单的功能,比如制作图片轮播/网页的tab等等,这篇文章将向你展示如何在自己的网页上制作拖拽.

    有很多理由让你的网站加入拖拽功能,最简单的一个是数据重组.例如:你有一个序列的内容让用户排序,用户需要给每个条目进行输入或者用select 选择,替代前面这个方法的就是拖拽.或许你的网站也需要一个用户可以拖动的导航窗口!那么这些效果都是很简单:因为你可以很容易的实现!

    网页上实现拖拽其实也不是很复杂.第一你需要知道鼠标坐标,第二你需要知道用户鼠标点击一个网页元素并实现拖拽,最后我们要实现移动这个元素.

    获取鼠标移动信息

    第一我们需要获取鼠标的坐标.我们加一个用户函数到document.onmousemove就可以了:

    document.onmousemove = mouseMove;

    function mouseMove(ev){
     ev           = ev || window.event;
     var mousePos = mouseCoords(ev);
    }

    function mouseCoords(ev){
     if(ev.pageX || ev.pageY){
      return {x:ev.pageX, y:ev.pageY};
     }
     return {
      x:ev.clientX + document.body.scrollLeft - document.body.clientLeft,
      y:ev.clientY + document.body.scrollTop  - document.body.clientTop
     };
    }


    <SCRIPT 
          
    src="/articleimg/2006/07/3791/drag_drop.js" 
          type
    =text/javascript></SCRIPT>
    <STYLE type=text/css>LI {
        MARGIN-BOTTOM
    : 10px
    }
    OL 
    {
        MARGIN-TOP
    : 5px
    }
    .DragContainer 
    {
        BORDER-RIGHT
    : #669999 2px solid; PADDING-RIGHT: 5px; BORDER-TOP: #669999 2px solid; PADDING-LEFT: 5px; FLOAT: left; PADDING-BOTTOM: 0px; MARGIN: 3px; BORDER-LEFT: #669999 2px solid; WIDTH: 100px; PADDING-TOP: 5px; BORDER-BOTTOM: #669999 2px solid
    }
    .OverDragContainer 
    {
        BORDER-RIGHT
    : #669999 2px solid; PADDING-RIGHT: 5px; BORDER-TOP: #669999 2px solid; PADDING-LEFT: 5px; FLOAT: left; PADDING-BOTTOM: 0px; MARGIN: 3px; BORDER-LEFT: #669999 2px solid; WIDTH: 100px; PADDING-TOP: 5px; BORDER-BOTTOM: #669999 2px solid
    }
    .OverDragContainer 
    {
        BACKGROUND-COLOR
    : #eee
    }
    .DragBox 
    {
        BORDER-RIGHT
    : #000 1px solid; PADDING-RIGHT: 2px; BORDER-TOP: #000 1px solid; PADDING-LEFT: 2px; FONT-SIZE: 10px; MARGIN-BOTTOM: 5px; PADDING-BOTTOM: 2px; BORDER-LEFT: #000 1px solid; WIDTH: 94px; CURSOR: pointer; PADDING-TOP: 2px; BORDER-BOTTOM: #000 1px solid; FONT-FAMILY: verdana, tahoma, arial; BACKGROUND-COLOR: #eee
    }
    .OverDragBox 
    {
        BORDER-RIGHT
    : #000 1px solid; PADDING-RIGHT: 2px; BORDER-TOP: #000 1px solid; PADDING-LEFT: 2px; FONT-SIZE: 10px; MARGIN-BOTTOM: 5px; PADDING-BOTTOM: 2px; BORDER-LEFT: #000 1px solid; WIDTH: 94px; CURSOR: pointer; PADDING-TOP: 2px; BORDER-BOTTOM: #000 1px solid; FONT-FAMILY: verdana, tahoma, arial; BACKGROUND-COLOR: #eee
    }
    .DragDragBox 
    {
        BORDER-RIGHT
    : #000 1px solid; PADDING-RIGHT: 2px; BORDER-TOP: #000 1px solid; PADDING-LEFT: 2px; FONT-SIZE: 10px; MARGIN-BOTTOM: 5px; PADDING-BOTTOM: 2px; BORDER-LEFT: #000 1px solid; WIDTH: 94px; CURSOR: pointer; PADDING-TOP: 2px; BORDER-BOTTOM: #000 1px solid; FONT-FAMILY: verdana, tahoma, arial; BACKGROUND-COLOR: #eee
    }
    .miniDragBox 
    {
        BORDER-RIGHT
    : #000 1px solid; PADDING-RIGHT: 2px; BORDER-TOP: #000 1px solid; PADDING-LEFT: 2px; FONT-SIZE: 10px; MARGIN-BOTTOM: 5px; PADDING-BOTTOM: 2px; BORDER-LEFT: #000 1px solid; WIDTH: 94px; CURSOR: pointer; PADDING-TOP: 2px; BORDER-BOTTOM: #000 1px solid; FONT-FAMILY: verdana, tahoma, arial; BACKGROUND-COLOR: #eee
    }
    .OverDragBox 
    {
        BACKGROUND-COLOR
    : #ffff99
    }
    .DragDragBox 
    {
        BACKGROUND-COLOR
    : #ffff99
    }
    .DragDragBox 
    {
        FILTER
    : alpha(opacity=50); BACKGROUND-COLOR: #ff99cc
    }
    LEGEND 
    {
        FONT-WEIGHT
    : bold; FONT-SIZE: 12px; COLOR: #666699; FONT-FAMILY: verdana, tahoma, arial
    }
    FIELDSET 
    {
        PADDING-RIGHT
    : 3px; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; PADDING-TOP: 3px
    }
    .History 
    {
        FONT-SIZE
    : 10px; OVERFLOW: auto; WIDTH: 100%; FONT-FAMILY: verdana, tahoma, arial; HEIGHT: 82px
    }
    #DragContainer8 
    {
        BORDER-RIGHT
    : #669999 1px solid; PADDING-RIGHT: 0px; BORDER-TOP: #669999 1px solid; PADDING-LEFT: 5px; PADDING-BOTTOM: 0px; BORDER-LEFT: #669999 1px solid; WIDTH: 110px; PADDING-TOP: 5px; BORDER-BOTTOM: #669999 1px solid; HEIGHT: 110px
    }
    .miniDragBox 
    {
        FLOAT
    : left; MARGIN: 0px 5px 5px 0px; WIDTH: 20px; HEIGHT: 20px
    }
    PRE 
    {
        BORDER-RIGHT
    : #ccc 1px solid; PADDING-RIGHT: 10px; BORDER-TOP: #ccc 1px solid; PADDING-LEFT: 10px; PADDING-BOTTOM: 10px; BORDER-LEFT: #ccc 1px solid; PADDING-TOP: 10px; BORDER-BOTTOM: #ccc 1px solid; BACKGROUND-COLOR: #f8f8f0
    }
    </STYLE>
    <body>
    <FIELDSET id=Demo4><LEGEND>样例- 拖拽页面元素</LEGEND>
          
    <DIV>
          
    <DIV class=DragContainer id=DragContainer4 overclass="OverDragContainer">
          
    <DIV class=DragBox id=Item1 overclass="OverDragBox" 
          dragclass
    ="DragDragBox">Item #1</DIV>
          
    <DIV class=DragBox id=Item2 overclass="OverDragBox" 
          dragclass
    ="DragDragBox">Item #2</DIV>
          
    <DIV class=DragBox id=Item3 overclass="OverDragBox" 
          dragclass
    ="DragDragBox">Item #3</DIV>
          
    <DIV class=DragBox id=Item4 overclass="OverDragBox" 
          dragclass
    ="DragDragBox">Item #4</DIV></DIV>
          
    <DIV class=DragContainer id=DragContainer5 overclass="OverDragContainer">
          
    <DIV class=DragBox id=Item5 overclass="OverDragBox" 
          dragclass
    ="DragDragBox">Item #5</DIV>
          
    <DIV class=DragBox id=Item6 overclass="OverDragBox" 
          dragclass
    ="DragDragBox">Item #6</DIV>
          
    <DIV class=DragBox id=Item7 overclass="OverDragBox" 
          dragclass
    ="DragDragBox">Item #7</DIV>
          
    <DIV class=DragBox id=Item8 overclass="OverDragBox" 
          dragclass
    ="DragDragBox">Item #8</DIV></DIV>
          
    <DIV class=DragContainer id=DragContainer6 overclass="OverDragContainer">
          
    <DIV class=DragBox id=Item9 overclass="OverDragBox" 
          dragclass
    ="DragDragBox">Item #9</DIV>
          
    <DIV class=DragBox id=Item10 overclass="OverDragBox" 
          dragclass
    ="DragDragBox">Item #10</DIV>
          
    <DIV class=DragBox id=Item11 overclass="OverDragBox" 
          dragclass
    ="DragDragBox">Item #11</DIV>
          
    <DIV class=DragBox id=Item12 overclass="OverDragBox" 
          dragclass
    ="DragDragBox">Item #12</DIV></DIV></DIV></FIELDSET>
    </body>

    </html>

    代码

    <script>

    function mouseMove(ev){
        ev           
    = ev || window.event;
        
    var mousePos = mouseCoords(ev);
            document.getElementById(
    'xxx').value = mousePos.x;
            document.getElementById(
    'yyy').value = mousePos.y;
    }

    function mouseCoords(ev){
        
    if(ev.pageX || ev.pageY){
            
    return {x:ev.pageX, y:ev.pageY};
        }
        
    return {
            x:ev.clientX 
    + document.body.scrollLeft - document.body.clientLeft,
            y:ev.clientY 
    + document.body.scrollTop  - document.body.clientTop
        };
    }

    document.onmousemove 
    = mouseMove;
    </script>Mouse X Position:
    <input id=xxx type=text>
    <br>Mouse Y Position:
    <input id=yyy type=text>

    你首先要声明一个evnet对象.不论何时你移动鼠标/点击/按键等等,会对应一个event的事件.在Internet Explorer里event是全局变量,会被存储在window.event里. 在firefox中,或者其他浏览器,event事件会被相应的自定义函数获取.当我们将mouseMove函数赋值于document.onmousemove,mouseMove会获取鼠标移动事件.

    (ev = ev || window.event) 这样让ev在所有浏览器下获取了event事件,在Firefox下"||window.event"将不起作用,因为ev已经有了赋值.在MSIE下ev是空的,所以ev将设置为window.event.

    因为我们在这篇文章中需要多次获取鼠标坐标,所以我们设计了mouseCoords这个函数,它只包含了一个参数,就是the event.

    我们需要运行在MSIE与Firefox为首的其他浏览器下.Firefox以event.pageX和event.pageY来代表鼠标相应于文 档左上角的位置.如果你有一个500*500的窗口,而且你的鼠标在正中间,那么paegX和pageY将是250,当你将页面往下滚动500px,那么 pageY将是750.此时pageX不变,还是250.

    MSIE和这个相反,MSIE将event.clientX与event.clientY来代表鼠标与ie窗口的位置,并不是文档.当我们有一个 500*500的窗口,鼠标在正中间,那么clientX与clientY也是250,如果你垂直滚动窗口到任何位置,clientY仍然是250,因为 相对ie窗口并没有变化.想得到正确的结果,我们必须加入scrollLeft与scrollTop这两个相对于文档鼠标位置的属性.最后,由于MSIE 并没有0,0的文档起始位置,因为通常会设置2px的边框在周围,边框的宽度包含在document.body.clientLeft与 clientTop这两个属性中,我们再加入这些到鼠标的位置中.

    很幸运,这样mouseCoords函数就完成了,我们不再为坐标的事操心了.

    捕捉鼠标点击

    下次我们将知道鼠标何时点击与何时放开.如果我们跳过这一步,我们在做拖拽时将永远不知道鼠标移动上面时的动作,这将是恼人的与违反直觉的.

    这里有两个函数帮助我们:onmousedown与onmouseup.我们预先设置函数来接收document.onmousemove,这样看 起来很象我们会获取document.onmousedown与document.onmouseup.但是当我们获取 document.onmousedown时,我们同时获取了任何对象的点击属性如:text,images,tables等等.我们只想获取那些需要拖 拽的属性,所以我们设置函数来获取我们需要移动的对象.

    <script>
    function mouseDown(ev){
        ev         
    = ev || window.event;
        
    var target = ev.target || ev.srcElement;

        
    if(target.onmousedown || target.getAttribute('DragObj')){
            
    return false;
        }
    }

    function makeClickable(item){
        
    if(!item) return;
        item.onmousedown 
    = function(ev){
            document.getElementById(
    'ClickImage').value = this.name;
        }
    }
    document.onmousedown 
    = mouseDown;
    window.onload 
    = function(){
        makeClickable(document.getElementById(
    'ClickImage1'));
        makeClickable(document.getElementById(
    'ClickImage2'));
        makeClickable(document.getElementById(
    'ClickImage3'));
        makeClickable(document.getElementById(
    'ClickImage4'));
    }
    </script>

    <FIELDSET id=Demo3>
    <h3>
      Demo - Click any image
    </h3>
    <IMG id=ClickImage1 
    src="/articleimg/2006/07/3791/drag_drop_spade.gif" 
    name
    =Spade><IMG id=ClickImage2 
    src="/articleimg/2006/07/3791/drag_drop_heart.gif" 
    name
    =Heart><IMG id=ClickImage3 
    src="/articleimg/2006/07/3791/drag_drop_diamond.gif" 
    name
    =Diamond><IMG id=ClickImage4 
    src="/articleimg/2006/07/3791/drag_drop_club.gif"
     name
    =Club> 
    <BR>You clicked on: <INPUT id=ClickImage type="text"> </FIELDSET>

    移动一个元素

    我们知道了怎么捕捉鼠标移动与点击.剩下的就是移动元素了.首先,要确定一个明确的页面位置,css样式表 要用'absolute'.设置元素绝对位置意味着我们可以用样式表的.top和.left来定位,可以用相对位置来定位了.我们将鼠标的移动全部相对页 面top-left,基于这点,我们可以进行下一步了.

    当我们定义item.style.position='absolute',所有的操作都是改变left坐标与top坐标,然后它移动了.

    document.onmousemove = mouseMove;
    document.onmouseup   = mouseUp;

    var dragObject  = null;
    var mouseOffset = null;

    function getMouseOffset(target, ev){
     ev = ev || window.event;

     var docPos    = getPosition(target);
     var mousePos  = mouseCoords(ev);
     return {x:mousePos.x - docPos.x, y:mousePos.y - docPos.y};
    }

    function getPosition(e){
     var left = 0;
     var top  = 0;

     while (e.offsetParent){
      left += e.offsetLeft;
      top  += e.offsetTop;
      e     = e.offsetParent;
     }

     left += e.offsetLeft;
     top  += e.offsetTop;

     return {x:left, y:top};
    }

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

     if(dragObject){
      dragObject.style.position = 'absolute';
      dragObject.style.top      = mousePos.y - mouseOffset.y;
      dragObject.style.left     = mousePos.x - mouseOffset.x;

      return false;
     }
    }
    function mouseUp(){
     dragObject = null;
    }

    function makeDraggable(item){
     if(!item) return;
     item.onmousedown = function(ev){
      dragObject  = this;
      mouseOffset = getMouseOffset(this, ev);
      return false;
     }

    }

    你会注意到这个代码几乎是前面的全集,将前面的合在一起就实现了拖拽效果了.

    当我们点击一个item时,我们就获取了很多变量,如鼠标位置,鼠标位置自然就包含了那个item的坐标信 息了.如果我们点击了一个20*20px图像的正中间,那么鼠标的相对坐标为{x:10,y:10}.当我们点击这个图像的左上角那么鼠标的相对坐标为 {x:0,y:0}.当我们点击时,我们用这个方法取得一些鼠标与图片校对的信息.如果我们不能加载页面item,那么信息将是document信息,会 忽略了点击的item信息.

    mouseOffset函数使用了另一个函数getPosition.getPosition的作用是返回 item相对页面左上角的坐标,如果我们尝试获取item.offsetLeft或者item.style.left,那么我们将取得item相对与父级 的位置,不是整个document.所有的脚本我们都是相对整个document,这样会更好一些.

    为了完成getPosition任务,必须循环取得item的父级,我们将加载内容到item的左/上的位置.我们需要管理想要的top与left列表.

    自从定义了mousemove这个函数,mouseMove就会一直运行.第一我们确定item的 style.position为absolute,第二我们移动item到前面定义好的位置.当mouse点击被释放,dragObject被设置为 null,mouseMove将不在做任何事.

    Dropping an Item

    前面的例子目的很简单,就是拖拽item到我们希望到的地方.我们经常还有其他目的如删除item,比如我们可以将item拖到垃圾桶里,或者其他页面定义的位置.

    很不幸,我们有一个很大的难题,当我们拖拽,item会在鼠标之下,比如mouseove,mousedown,mouseup或者其他mouse action.如果我们拖拽一个item到垃圾桶上,鼠标信息还在item上,不在垃圾桶上.

    怎么解决这个问题呢?有几个方法可以来解决.第一,这是以前比较推荐的,我们在移动鼠标时item会跟随鼠 标,并占用了mouseover/mousemove等鼠标事件,我们不这样做,只是让item跟随着鼠标,并不占用mouseover等鼠标事件,这样 会解决问题,但是这样并不好看,我们还是希望item能直接跟在mouse下.

    另一个选择是不做item的拖拽.你可以改变鼠标指针来显示需要拖拽的item,然后放在鼠标释放的位置.这个解决方案,也是因为美学原因不予接受.

    最后的解决方案是,我们并不去除拖拽效果.这种方法比前两种繁杂许多,我们需要定义我们需要释放目标的列表,当鼠标释放时,手工去检查释放的位置是否是在目标列表位置上,如果在,说明是释放在目标位置上了.

    /*
    All code from the previous example is needed with the exception
    of the mouseUp function which is replaced below
    */

    var dropTargets = [];

    function addDropTarget(dropTarget){
     dropTargets.push(dropTarget);
    }

    function mouseUp(ev){
     ev           = ev || window.event;
     var mousePos = mouseCoords(ev);

     for(var i=0; i<dropTargets.length; i++){
      var curTarget  = dropTargets[i];
      var targPos    = getPosition(curTarget);
      var targWidth  = parseInt(curTarget.offsetWidth);
      var targHeight = parseInt(curTarget.offsetHeight);

      if(
       (mousePos.x > targPos.x)                &&

       (mousePos.x < (targPos.x + targWidth))  &&
       (mousePos.y > targPos.y)                &&
       (mousePos.y < (targPos.y + targHeight))){
        // dragObject was dropped onto curTarget!
      }
     }

     dragObject   = null;

    }

    鼠标释放时会去取是否有drop属性,如果存在,同时鼠标指针还在drop的范围内,执行drop操作.我们检查鼠标指针位置是否在目 标范围是用(mousePos.x>targetPos.x),而且还要符合条件(mousePos.x<(targPos.x + targWidth)).如果所有的条件符合,说明指针确实在范围内,可以执行drop指令了.

    Pulling It All Together

    最后我们拥有了所有的drag/drop的脚本片断!下一个事情是我们将创建一个DOM处理.如果你不是很熟悉,请先阅读我的JavaScript Primer on DOM Manipulation.

    下面的代码将创建container(容器),而且使任何一个需要drag/drop的item变成一个容器的item.代码在这个文章第二个demo的后面,它可以用户记录一个list(列表),定为一个导航窗口在左边或者右边,或者更多的函数你可以想到的.

    下一步我们将通过"假代码"让reader看到真代码,下面为推荐:

    1、当document第一次载入时,创建dragHelper DIV.dragHelper将给移动的item加阴影.真实的item没有被dragged,只是用了insertBefor和appendChild来移动了,我们隐藏了dragHelper

    2、有了mouseDown与mouseUp函数.所有的操作会对应到当到iMouseDown的状态中,只有当mouse左键为按下时iMouseDown才为真,否则为假.

    3、我们创建了全局变量DragDrops与全局函数CreateDragContainer.DragDrops包含了一系列相对彼 此的容器.任何参数(containers)将通过CreatedcragContainer进行重组与序列化,这样可以自由的移 动.CreateDragContainer函数也将item进行绑定与设置属性.

    4、现在我们的代码知道每个item的加入,当我们移动处mouseMove,mouseMove函数首先会设置变量target,鼠标移动在上面的item,如果这个item在容器中(checked with getAttribute):

    • 运行一小段代码来改变目标的样式.创造rollover效果
    • 检查鼠标是否没有放开,如果没有
      • 设置curTarget代表当前item
      • 记录item的当前位置,如果需要的话,我们可以将它返回
      • 克隆当前的item到dragHelper中,我们可以移动带阴影效果的item.
      • item拷贝到dragHelper后,原有的item还在鼠标指针下,我们必须删除掉dragObj,这样脚本起作用,dragObj被包含在一个容器中.
      • 抓取容器中所有的item当前坐标,高度/宽度,这样只需要记录一次,当item被drag时,每随mouse移动,每移钟就会记录成千上万次.
    • 如果没有,不需要做任何事,因为这不是一个需要移动的item

    5、检查curTarget,它应该包含一个被移动的item,如果存在,进行下面操作:

    • 开始移动带有阴影的item,这个item就是前文所创建的
    • 检查每个当前容器中的container,是否鼠标已经移动到这些范围内了
      • 我们检查看一下正在拖动的item是属于哪个container
      • 放置item在一个container的某一个item之前,或者整个container之后
      • 确认item是可见的
    • 如果鼠标不在container中,确认item是不可见了.

    6、剩下的事就是捕捉mouseUp的事件了

     实现一个拖动的全代码:

    Code
  • 相关阅读:
    闭包
    laravel 控制器
    laravel 模板
    laravel 视图
    laravel 请求
    laravel 分页
    解决启动Apache遇到的问题Permission denied: AH00072: make_sock: could not bind to address 0.0.0.0:8888
    一张号称一篇程序覆盖Python基础的代码
    [转载]激活Navicat Premium
    C语言自定义函数的形参为数组时需要注意传入长度
  • 原文地址:https://www.cnblogs.com/goody9807/p/1365239.html
Copyright © 2020-2023  润新知