标签:style blog color os io for ar cti
在某个时刻, 我认识了一个朋友.
此人在我的教唆下, 踏上了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 else 237 { 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 -= frameY 267 }; 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状态.
js 实现win7任务栏拖动效果,布布扣,bubuko.com
标签:style blog color os io for ar cti
原文地址:http://www.cnblogs.com/mmc1206x/p/3901281.html