首页 > 代码库 > js 实现win7任务栏拖动效果

js 实现win7任务栏拖动效果

<style></style>

前言

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

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

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

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

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

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

 

 

源码

话不多说, 上源码.

  1 //    常量  2 var CELL_WIDTH    = 100;  3 var CELL_HEIGHT = 50;  4   5 var Utils = {  6     pixelToInt: function(str)  7     {  8         return parseInt( str.replace("px", "") );  9     },  10     getTagLeft: function($tag) 11     { 12         return this.pixelToInt( $tag.css("left") ); 13     }, 14     getTagTop: function($tag) 15     { 16         return this.pixelToInt( $tag.css("top") ); 17     }, 18     getTagWidth: function($tag) 19     { 20         return this.pixelToInt( $tag.css("width") ); 21     }, 22     getTagHeight: function($tag) 23     { 24         return this.pixelToInt( $tag.css("height") ); 25     }, 26     setTagLeft: function($tag, x) 27     { 28         $tag.css("left", x + "px"); 29     }, 30     setTagTop: function($tag, y) 31     { 32         $tag.css("top", y + "px"); 33     }, 34     setTagWidth: function($tag, width) 35     { 36         $tag.css("width", width + "px"); 37     }, 38     setTagHeight: function($tag, height) 39     { 40         $tag.css("left", height + "px"); 41     }, 42     swapNode: function(ary, idx1, idx2) 43     { 44         var t = ary[idx1]; 45         ary[idx1] = ary[idx2]; 46         ary[idx2] = t; 47     } 48 }; 49  50 function Taskbar() 51 { 52     this._cells = []; 53     this._frameTag = null; 54     this._cellWidth = 0; 55     this._cellHeight = 0; 56     this._selNode = null; 57     this._selIndex = -1; 58  59     this._swapQueue = []; 60     //    考虑优化. 61     this._offsetPoint = {"x": 0, "y": 0}; 62 } 63  64 Taskbar.prototype.getTag = function() 65 { 66     return this._frameTag; 67 } 68  69 Taskbar.prototype.init = function(x, y, width, height, rgb) 70 { 71     this._frameTag = $("<div></div>"); 72     this.setPosition(x, y); 73     this.setContentSize(width, height); 74     this.setBackgroundColor(rgb); 75  76     var self = this; 77     this._frameTag.bind("mousedown", {"bar": self}, this.mouseDown); 78     this._frameTag.bind("mouseup", {"bar": self}, this.mouseUp); 79     this._frameTag.bind("mousemove", {"bar": self}, this.mouseMove); 80     // this._frameTag.bind("mouseout", {"bar": self}, this.mouseOut); 81 } 82  83 Taskbar.prototype.setPosition = function(x, y) 84 { 85     this._frameTag.css("position", "absolute"); 86     this._frameTag.css("left", x + "px"); 87     this._frameTag.css("top", y + "px"); 88 } 89  90 Taskbar.prototype.setContentSize = function(width, height) 91 { 92     this._frameTag.css("width", width + "px"); 93     this._frameTag.css("height", height + "px"); 94 } 95  96 Taskbar.prototype.setBackgroundColor = function(rgb) 97 { 98     //    rgb => "rgb(0, 0, 0)". 99     this._frameTag.css("background", rgb);100 }101 102 Taskbar.prototype.appendNode = function($node)103 {104     var frameWidth = Utils.getTagWidth( this._frameTag );105     var frameHeight = Utils.getTagHeight( this._frameTag );106     var length = this._cells.length + 1;107     this._cellWidth = frameWidth / length;108     this._cellHeight = frameHeight;109     this._cells.push($node);110     $node.appendTo( this._frameTag );111 112     for ( var i = 0; i != length; ++i )113     {114         Utils.setTagLeft( this._cells[i], i * this._cellWidth );115         Utils.setTagWidth( this._cells[i], this._cellWidth);116     }    117 }118 119 Taskbar.prototype.mouseDown = function(e)120 {121     var bar = e.data["bar"];122 123     if ( bar._selNode )124     {125         return ;126     }127 128     var index = bar.hitTest(e.clientX, e.clientY);129     if ( !bar.isInvalidIndex(index) )130     {131         //    激活.132         bar._selIndex = index;133         bar._selNode = bar._cells[ index ];134         bar._selNode.css("z-index", 99);135         bar._cells[ index ] = null;136 137         //    保存偏移量, 保持鼠标拖动.138         var point = bar.converPoint(e.clientX, e.clientY);139         bar._offsetPoint.x = point.x - index * bar._cellWidth;140         bar._offsetPoint.y = point.y;141         console.log("down");142     }143 144 }145 146 Taskbar.prototype.mouseUp = function(e)147 {148     var bar = e.data["bar"];149 150     if ( bar._selNode )151     {152         //    加入交换.153         bar.appendSwap(bar._selNode, bar._selIndex);154 155         //    鼠标抬起后, 把选中的节点复位.156         // bar._cells[ bar._selIndex ] = bar._selNode;157         bar._cells[ bar._selIndex ].css("z-index", 1);158         bar._selIndex = -1;159         bar._selNode = null;160         console.log("up");161     }162 }163 164 Taskbar.prototype.mouseOut = function(e)165 {166     var bar = e.data["bar"];167     bar.mouseUp(e);168     console.log("mouseout");169 }170 171 Taskbar.prototype.mouseMove = function(e)172 {173     var bar = e.data["bar"];174     if ( bar._selNode )175     {176         var point = bar.converPoint(e.clientX, e.clientY);177         var moveX = point.x - bar._offsetPoint.x;178 179         //    防止位置溢出.180         bar.noOverflow( bar._selNode, moveX );181 182         //    挤开旁边的 float block.183         var curX = Utils.getTagLeft(bar._selNode),184             width = Utils.getTagWidth(bar._selNode),185             testX = curX + width / 2,186             hitIndex = bar.hitTest(testX, 0);187         if ( bar._selIndex != hitIndex )188         {189             bar.appendSwap(bar._cells[hitIndex], bar._selIndex);190             bar._selIndex = hitIndex;191         }192     }193 }194 195 Taskbar.prototype.appendSwap = function($node, index)196 {197     this._cells[index] = $node;198 199     this._swapQueue.push({"node": $node, "index": index});200     this.resetNode();201 }202 203 Taskbar.prototype.noOverflow = function($node, moveX)204 {205     var width = Utils.getTagWidth( $node ),206         frameWidth = Utils.getTagWidth( this._frameTag );207 208     if (moveX < 0)209         moveX = 0;210     else if ( moveX + width > frameWidth )211         moveX = frameWidth - width;212 213     Utils.setTagLeft( $node, moveX );214 }215 216 Taskbar.prototype.resetNode = function()217 {218     var self = this;219     var call = function($node, index)220     {221         var oldX = Utils.getTagLeft($node),222             newX = index * self._cellWidth,223             diff = newX - oldX,224             stepCount = 10,225             step = diff / stepCount,226             curX = oldX;227         (228             function call()229             {230                 if ( stepCount != 0 )231                 {232                     curX += step;233                     Utils.setTagLeft($node, curX);234                     setTimeout(call, 10);235                 }236                 else237                 {238                     $node.css("z-index", 0);239                     Utils.setTagLeft($node, newX);240                 }241                 --stepCount;242             }243         )();244     };245 246     for (var i in this._swapQueue)247     {248         call(this._swapQueue[i].node, this._swapQueue[i].index);249     }250     this._swapQueue = [];251 }252 253 Taskbar.prototype.hitTest = function(x, y)254 {255     //    y参数完全是个酱油.256     var point = this.converPoint(x, y);257     return parseInt(point.x / this._cellWidth);258 }259 260 Taskbar.prototype.converPoint = function(x, y)261 {262     var frameX = Utils.getTagLeft( this._frameTag );263         frameY = Utils.getTagTop( this._frameTag );264     return {265         "x": x -= frameX,266         "y": y -= frameY267     };268 }269 270 Taskbar.prototype.isInvalidIndex = function(index)271 {272     return index < 0 || index >= this._cells.length;273 }274 275 function init()276 {277     var getCell = function(cls, left, top, name)278     {279         return $(280             "<div class=‘_cls‘ name=‘_name‘ style=‘left: _leftpx; top: _toppx; width: _widthpx; height: _heightpx;‘></div>"281             .replace("_cls", cls)282             .replace("_left", left)283             .replace("_top", top)284             .replace("_name", name)285             .replace("_width", CELL_WIDTH)286             .replace("_height", CELL_HEIGHT) );287     };288 289     // for (var i = 0; i != 5; ++i)290     // {291     //     var taskbar = new Taskbar();292     //     taskbar.init(0, i * 60, 500, 50, "rgb(0, 0, 0)");293     //     taskbar.getTag().appendTo( $("body") );294     //     for (var j = 0; j != i + 5; ++j)295     //     {296     //         taskbar.appendNode( getCell("cell", 0, 0, 0) );297     //     }298     // }299 }300 301 $(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状态.