前言

在某个时刻, 我认识了一个朋友.

此人在我的教唆下, 踏上了js的不归路.

前天他问我, Win7任务栏拖动效果怎么实现.

我随口就跟他说, 这简单的一逼.

在我一晚上的折腾之后, 一份潦草的代码总算实现了功能.

PS: 我是搞C++的, js略懂一二..

源码

话不多说, 上源码.

 //    常量
 var CELL_WIDTH    = 100;
 var CELL_HEIGHT = 50;

 var Utils = {
     pixelToInt: function(str)
     {
         return parseInt( str.replace("px", "") );
     },
     getTagLeft: function($tag)
     {
         return this.pixelToInt( $tag.css("left") );
     },
     getTagTop: function($tag)
     {
         return this.pixelToInt( $tag.css("top") );
     },
     getTagWidth: function($tag)
     {
         return this.pixelToInt( $tag.css("width") );
     },
     getTagHeight: function($tag)
     {
         return this.pixelToInt( $tag.css("height") );
     },
     setTagLeft: function($tag, x)
     {
         $tag.css("left", x + "px");
     },
     setTagTop: function($tag, y)
     {
         $tag.css("top", y + "px");
     },
     setTagWidth: function($tag, width)
     {
         $tag.css("width", width + "px");
     },
     setTagHeight: function($tag, height)
     {
         $tag.css("left", height + "px");
     },
     swapNode: function(ary, idx1, idx2)
     {
         var t = ary[idx1];
         ary[idx1] = ary[idx2];
         ary[idx2] = t;
     }
 };

 function Taskbar()
 {
     this._cells = [];
     this._frameTag = null;
     this._cellWidth = 0;
     this._cellHeight = 0;
     this._selNode = null;
     this._selIndex = -1;

     this._swapQueue = [];
     //    考虑优化.
     this._offsetPoint = {"x": 0, "y": 0};
 }

 Taskbar.prototype.getTag = function()
 {
     return this._frameTag;
 }

 Taskbar.prototype.init = function(x, y, width, height, rgb)
 {
     this._frameTag = $("<div></div>");
     this.setPosition(x, y);
     this.setContentSize(width, height);
     this.setBackgroundColor(rgb);

     var self = this;
     this._frameTag.bind("mousedown", {"bar": self}, this.mouseDown);
     this._frameTag.bind("mouseup", {"bar": self}, this.mouseUp);
     this._frameTag.bind("mousemove", {"bar": self}, this.mouseMove);
     // this._frameTag.bind("mouseout", {"bar": self}, this.mouseOut);
 }

 Taskbar.prototype.setPosition = function(x, y)
 {
     this._frameTag.css("position", "absolute");
     this._frameTag.css("left", x + "px");
     this._frameTag.css("top", y + "px");
 }

 Taskbar.prototype.setContentSize = function(width, height)
 {
     this._frameTag.css("width", width + "px");
     this._frameTag.css("height", height + "px");
 }

 Taskbar.prototype.setBackgroundColor = function(rgb)
 {
     //    rgb => "rgb(0, 0, 0)".
     this._frameTag.css("background", rgb);
 }

 Taskbar.prototype.appendNode = function($node)
 {
     var frameWidth = Utils.getTagWidth( this._frameTag );
     var frameHeight = Utils.getTagHeight( this._frameTag );
     var length = this._cells.length + 1;
     this._cellWidth = frameWidth / length;
     this._cellHeight = frameHeight;
     this._cells.push($node);
     $node.appendTo( this._frameTag );

     for ( var i = 0; i != length; ++i )
     {
         Utils.setTagLeft( this._cells[i], i * this._cellWidth );
         Utils.setTagWidth( this._cells[i], this._cellWidth);
     }
 }

 Taskbar.prototype.mouseDown = function(e)
 {
     var bar = e.data["bar"];

     if ( bar._selNode )
     {
         return ;
     }

     var index = bar.hitTest(e.clientX, e.clientY);
     if ( !bar.isInvalidIndex(index) )
     {
         //    激活.
         bar._selIndex = index;
         bar._selNode = bar._cells[ index ];
         bar._selNode.css("z-index", 99);
         bar._cells[ index ] = null;

         //    保存偏移量, 保持鼠标拖动.
         var point = bar.converPoint(e.clientX, e.clientY);
         bar._offsetPoint.x = point.x - index * bar._cellWidth;
         bar._offsetPoint.y = point.y;
         console.log("down");
     }

 }

 Taskbar.prototype.mouseUp = function(e)
 {
     var bar = e.data["bar"];

     if ( bar._selNode )
     {
         //    加入交换.
         bar.appendSwap(bar._selNode, bar._selIndex);

         //    鼠标抬起后, 把选中的节点复位.
         // bar._cells[ bar._selIndex ] = bar._selNode;
         bar._cells[ bar._selIndex ].css("z-index", 1);
         bar._selIndex = -1;
         bar._selNode = null;
         console.log("up");
     }
 }

 Taskbar.prototype.mouseOut = function(e)
 {
     var bar = e.data["bar"];
     bar.mouseUp(e);
     console.log("mouseout");
 }

 Taskbar.prototype.mouseMove = function(e)
 {
     var bar = e.data["bar"];
     if ( bar._selNode )
     {
         var point = bar.converPoint(e.clientX, e.clientY);
         var moveX = point.x - bar._offsetPoint.x;

         //    防止位置溢出.
         bar.noOverflow( bar._selNode, moveX );

         //    挤开旁边的 float block.
         var curX = Utils.getTagLeft(bar._selNode),
             width = Utils.getTagWidth(bar._selNode),
             testX = curX + width / 2,
             hitIndex = bar.hitTest(testX, 0);
         if ( bar._selIndex != hitIndex )
         {
             bar.appendSwap(bar._cells[hitIndex], bar._selIndex);
             bar._selIndex = hitIndex;
         }
     }
 }

 Taskbar.prototype.appendSwap = function($node, index)
 {
     this._cells[index] = $node;

     this._swapQueue.push({"node": $node, "index": index});
     this.resetNode();
 }

 Taskbar.prototype.noOverflow = function($node, moveX)
 {
     var width = Utils.getTagWidth( $node ),
         frameWidth = Utils.getTagWidth( this._frameTag );

     if (moveX < 0)
         moveX = 0;
     else if ( moveX + width > frameWidth )
         moveX = frameWidth - width;

     Utils.setTagLeft( $node, moveX );
 }

 Taskbar.prototype.resetNode = function()
 {
     var self = this;
     var call = function($node, index)
     {
         var oldX = Utils.getTagLeft($node),
             newX = index * self._cellWidth,
             diff = newX - oldX,
             stepCount = 10,
             step = diff / stepCount,
             curX = oldX;
         (
             function call()
             {
                 if ( stepCount != 0 )
                 {
                     curX += step;
                     Utils.setTagLeft($node, curX);
                     setTimeout(call, 10);
                 }
                 else
                 {
                     $node.css("z-index", 0);
                     Utils.setTagLeft($node, newX);
                 }
                 --stepCount;
             }
         )();
     };

     for (var i in this._swapQueue)
     {
         call(this._swapQueue[i].node, this._swapQueue[i].index);
     }
     this._swapQueue = [];
 }

 Taskbar.prototype.hitTest = function(x, y)
 {
     //    y参数完全是个酱油.
     var point = this.converPoint(x, y);
     return parseInt(point.x / this._cellWidth);
 }

 Taskbar.prototype.converPoint = function(x, y)
 {
     var frameX = Utils.getTagLeft( this._frameTag );
         frameY = Utils.getTagTop( this._frameTag );
     return {
         "x": x -= frameX,
         "y": y -= frameY
     };
 }

 Taskbar.prototype.isInvalidIndex = function(index)
 {
     return index < 0 || index >= this._cells.length;
 }

 function init()
 {
     var getCell = function(cls, left, top, name)
     {
         return $(
             "<div class='_cls' name='_name' style='left: _leftpx; top: _toppx; width: _widthpx; height: _heightpx;'></div>"
             .replace("_cls", cls)
             .replace("_left", left)
             .replace("_top", top)
             .replace("_name", name)
             .replace("_width", CELL_WIDTH)
             .replace("_height", CELL_HEIGHT) );
     };

      for (var i = 0; i != 5; ++i)
      {
          var taskbar = new Taskbar();
          taskbar.init(0, i * 60, 500, 50, "rgb(0, 0, 0)");
          taskbar.getTag().appendTo( $("body") );
          for (var j = 0; j != i + 5; ++j)
          {
              taskbar.appendNode( getCell("cell", 0, 0, 0) );
          }
      }
 }

 $(document).ready(init);

这个思路其实很简单.

创建一个Taskbar对象, 这个对象设定好坐标, 尺寸, 背景色.

随后往这个对象appendChild, 子节点会自动适配大小.

我们用一个 作业队列 来保存需要移动的任务.

这个队列保存需要被移动的节点, 和被动到哪个位置上.

随后会触发一个交换的动作, 这个动作是持续性的, 因此可以看到节点平滑移动.

在我们down下操作之后, 被down下的那个节点位置设置null.

随后我们用一个 _selNode 保存这个节点.

同时用 _selIndex 保存这个节点本应该属于的位置.(这句话很难形容, 但是我想不出怎么说!)

随后在move操作下, 判断这个 _selNode 是否"越线", 一旦越线则push一个交换作业.

随后就像上面所说, 触发交换动作.

在up操作触发之后, 只需要把 _selNode和_selIndex push到作业队列即可.

因为所有的mouse响应都在背景的div里, 因此鼠标超出范围则不会响应..

例如, 我down之后, 鼠标移出范围再up, 此时的up将不会被响应..

我在down中加了一条判断来解决此bug..

在超出范围up, 回到范围之后, 依然是down状态.

html 文件内容

<!DOCTYPE html>
<html>
<head>
<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript" src="xy.js"></script>

<style type="text/css">
    * {
        margin: 0;
        border: 0;
    }

    .cell {
        position: absolute;
        width: 100px;
        height: 50px;
        border: solid;
        background: rgb(21, 98, 231);
    }
</style>
</head>
<body>

</body>

</html>

之前写的匆忙, 只把脚本部分贴了上来, 漏掉了html文件.

js 实现win7任务栏拖动效果的更多相关文章

  1. HTML 通过js实现div的拖动效果

    最近做项目,碰到一个问题,需要对div实现拖动效果. 在度娘找了很多,要么觉得代码太长,要么就是效果不理想,不过最后还是找到了一个不错的,感谢大神的留贴,方便了我们,就把代码贴下面了: <!DO ...

  2. js实现一个可以兼容PC端和移动端的div拖动效果

    前段时间写了一个简单的div拖动效果,不料昨天项目上正好需要一个相差不多的需求,就正好用上了,但是在移动端的时候却碰到了问题,拖动时候用到的三个事件:mousedown.mousemove.mouse ...

  3. 通过html和css做出下拉导航栏的效果

    通过观察了百度的首页,对于更多产品一栏,觉得可以不涉及JS便可写出下拉导航栏的效果 1.先设计出大体的框架 <div class="nav"> <ul> & ...

  4. js鼠标滚轮滚动图片切换效果

    效果体验网址:http://keleyi.com/keleyi/phtml/image/12.htm HTML文件代码: <!DOCTYPE html PUBLIC "-//W3C// ...

  5. vc++ mfc中拖动效果的实现 借助于CImageList

    拖动是界面编程频繁使用的一个效果,在windows系统下可谓大行其道.纵观时下的应用软件几乎各个都支持各种各样拖动的效果,windows7更是把拖动做到了极致.其实说起来拖动的实现也很简单,对于有句柄 ...

  6. jquery div拖动效果示例代码

    div拖动效果想必大家都有见到过吧,实现的方法也是有很多的,下面为大家将介绍使用jquery是如何实现的,感兴趣的朋友不要错过 复制代码代码如下: <%@ page language=" ...

  7. js实现中文简繁切换效果

    html代码: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www ...

  8. Web的鼠标拖动效果

    以前写过一个拖动效果的Demo,拖拽元素新位置的计算是放在拖拽元素的mousemove事件中进行的.计算效率差,而且效果不好.所以一直有想怎样才能做出jquery-ui那种顺滑的拖拽效果. 其实顺滑的 ...

  9. jquery 实现导航栏滑动效果

    精简的代码实现导航栏滑动效果,实现详解: 1.滑块位置:通过父节点position=fixed,子节点position=absolute方式,实现子节点浮动: 2.导航栏居中:通过left=0px,r ...

随机推荐

  1. Word Pattern

    ​package cn.edu.xidian.sselab.hashtable; import java.util.HashMap;import java.util.Map; /** *  * @au ...

  2. 安装 macbook 双系统( OS X 和 Ubuntu )

    打算 macbook 上面多安装一个 ubuntu 系统来用下.流程大致下面几步: 1. 备份重要资料 2. 划分硬盘区域用于安装 ubuntu 3. 下载 ubuntu ISO 文件,并刻录到 U ...

  3. 你应该知道的8个Java牛人

    简单介绍一下8个Java牛人,他们为Java社区,创建了框架(framework),产品或者是写书,影响甚至改变了Java开发的方法 8.Tomcat创始人 James Duncan Davidson ...

  4. HttpURLConnection学习

    转自:http://mobile.51cto.com/abased-448264.htm 最常用的Http请求无非是get和post,get请求可以获取静态页面,也可以把参数放在URL字串后面,传递给 ...

  5. .gitignore模板

    github/gitignore · GitHub列举了一些有用的.gitignore的模板.比如这个是visual studio的. 另外说一个题外话,如果不想看见solution目录的那个sdf, ...

  6. WCF 项目应用连载[3] - 双向通信 实例管理与服务端监控

    WCF 项目应用连载[1] - 索引 - 轻量级的Log系统 - Lig Sample -序 第二节我们已经创建了Lig项目,并且能稳定工作了.现在我们来改进ILigAgent接口,实现WCF的双向通 ...

  7. 如何看懂Code128条形码

    条形码就是我们看到的商品上有的那些竖条条. 要不是项目上用到这个或许我一辈子也不会对那个感兴趣. 条形码其实是分成很多类的,虽然他们看起来都差不多…… 常见的条形码的码制被称为39码.128码.417 ...

  8. static作用——The static effect

    1)在函数体内,一个被声明为静态的变量在这一函数被调用过程中维持其值不变(该变量存放在静态变量区). 2) 在模块内(但在函数体外),一个被声明为静态的变量可以被模块内所用函数访问,但不能被模块外其它 ...

  9. DFU工作过程中USB机制

    在一级bootloader执行进入USB启动方式之后,设备进行枚举.枚举过程中会通过PC端发送命令对连接的USB设备进行枚举.当枚举成功之后,在PC端可以看到设备的盘符. 当设备能够被PC正确识别之后 ...

  10. 文字保护纱-Material Design

    Ok,关于这个Material Design 都快被说烂了,他被开发者越来越熟悉的程度,却与市场上的单薄身影形成了鲜明的对比,以至于每当我提及Material Design时就像祥林嫂附身一样. 有些 ...