js 实现win7任务栏拖动效果
前言
在某个时刻, 我认识了一个朋友.
此人在我的教唆下, 踏上了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任务栏拖动效果的更多相关文章
- HTML 通过js实现div的拖动效果
最近做项目,碰到一个问题,需要对div实现拖动效果. 在度娘找了很多,要么觉得代码太长,要么就是效果不理想,不过最后还是找到了一个不错的,感谢大神的留贴,方便了我们,就把代码贴下面了: <!DO ...
- js实现一个可以兼容PC端和移动端的div拖动效果
前段时间写了一个简单的div拖动效果,不料昨天项目上正好需要一个相差不多的需求,就正好用上了,但是在移动端的时候却碰到了问题,拖动时候用到的三个事件:mousedown.mousemove.mouse ...
- 通过html和css做出下拉导航栏的效果
通过观察了百度的首页,对于更多产品一栏,觉得可以不涉及JS便可写出下拉导航栏的效果 1.先设计出大体的框架 <div class="nav"> <ul> & ...
- js鼠标滚轮滚动图片切换效果
效果体验网址:http://keleyi.com/keleyi/phtml/image/12.htm HTML文件代码: <!DOCTYPE html PUBLIC "-//W3C// ...
- vc++ mfc中拖动效果的实现 借助于CImageList
拖动是界面编程频繁使用的一个效果,在windows系统下可谓大行其道.纵观时下的应用软件几乎各个都支持各种各样拖动的效果,windows7更是把拖动做到了极致.其实说起来拖动的实现也很简单,对于有句柄 ...
- jquery div拖动效果示例代码
div拖动效果想必大家都有见到过吧,实现的方法也是有很多的,下面为大家将介绍使用jquery是如何实现的,感兴趣的朋友不要错过 复制代码代码如下: <%@ page language=" ...
- js实现中文简繁切换效果
html代码: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www ...
- Web的鼠标拖动效果
以前写过一个拖动效果的Demo,拖拽元素新位置的计算是放在拖拽元素的mousemove事件中进行的.计算效率差,而且效果不好.所以一直有想怎样才能做出jquery-ui那种顺滑的拖拽效果. 其实顺滑的 ...
- jquery 实现导航栏滑动效果
精简的代码实现导航栏滑动效果,实现详解: 1.滑块位置:通过父节点position=fixed,子节点position=absolute方式,实现子节点浮动: 2.导航栏居中:通过left=0px,r ...
随机推荐
- Primary key and Unique index
SQL> create table t1(id1 char(2),id2 char(2),id3 char(2)); Table created. SQL> desc t1 Name Nu ...
- SDUT 最短路径(二维SPFA)
http://acm.sdut.edu.cn/sdutoj/problem.php?action=showproblem&problemid=2622 #include<stdio.h& ...
- Insertion Sort List —— LeetCode
Sort a linked list using insertion sort. 题目大意:将一个单链表使用插入排序的方式排序. 解题思路:先新建一个头指针,然后重新构建一下这个单链表,每次从头找到第 ...
- Listview加载更多是,恢复到原来的位置,如果不加特殊处理,总是跳转第一条
1.记录listView滚动到的位置的坐标,然后利用listView.scrollTo精确的进行恢复 listView.setOnScrollListener(new OnScrollListener ...
- First Record
今天我在博客园安家了! R Python Scala hadoop Spark MachineLearning
- 《University Calculus》-chaper8-无穷序列和无穷级数-等比级数
前言:其实无穷序列和无穷级数和数列{an}以及我们接触微积分就给出的极限概念lim有着紧密的联系,它对于我们在具体的问题当中进行建模和数据分析有着非常重要的作用. 无穷序列: 最简单的一种说法,就是一 ...
- 配置openStack使用spice
注:因为在测试配置过程中反复配置过多次,以下内容可能并不完整,有待验证. 按官方文档(openstack-install-guide-yum-juno)搭建和配置的OpenStack默认使用novnc ...
- 理解Java NIO
基础概念• 缓冲区操作缓冲区及操作是所有I/O的基础,进程执行I/O操作,归结起来就是向操作系统发出请求,让它要么把缓冲区里的数据排干(写),要么把缓冲区填满(读).如下图• 内核空间.用户空间 上图 ...
- java 编辑报错 非法字符: \ufeff 解决方案
用Notepad ++ 调成utf-8 格式 bom 或无bom根据情况 新建类 把代码一句句粘进去 ok
- 字符集转换 字符类型转换 utf-8 gb2312 url
vs默认是GB2312编码,你看到的程序源代码是,输出结果是,内部存储是, 1 如果你想改变内部存储可以用下面的这些函数 2 如果你想改变源代码的存储方式你可以用文本编辑工具修改之后重新编译 3 如果 ...