要實現的拖動效果:鼠標左鍵在窗口上方的標題欄上按下,同時移動鼠標,窗口跟著移動。
窗口:
復制代碼 代碼如下:
<div id="win">
<div id="win_header"></div>
</div>
一點准備工作:
要讓窗口能自由移動,那麼窗口的定位(position)應該采用絕對定位(absolute);
給窗口添加標題欄,這裡使用一個放在窗口頂部的層實現,同時將標題欄的鼠標光標設置為拖動(move)形狀(在chrome中拖動的時候,光標會變成文字光標,松開鼠標鍵後恢復)。
復制代碼 代碼如下:
#win {
position:absolute;
width:480px;
height:320px;
background-color:#d4d4d4;
border: 1px solid #4d4d4d;
}
#win_header {
width:480px;
height:48px;
background-color:#4d4d4d;
cursor:move;
}
定義一個工具函數,用來獲取指定ID屬性的元素:
復制代碼 代碼如下:
function $id(id) {
return document.getElementById(id);
}
定義一個浏覽器核心標識isIE:
var isIE = (window.navigator.userAgent.indexOf("IE") == -1) ? false : true;
獲取到窗口元素及其標題欄:
復制代碼 代碼如下:
var win = $id("win");
var header = $id("win_header");
為了方便記錄鼠標和窗口的位置信息,創建一個位置:
復制代碼 代碼如下:
var pos =function(x, y) {
this.x = x;
this.y = y;
};
給窗口設置一個初始位置(css的left值和top值)。
這裡不知道是為什麼,如果不使用js設置這兩個屬性,就取不到值,在CSS中指定了也不行。
復制代碼 代碼如下:
var originalpos = new pos(20, 20);
在拖動窗口的過程中,需要記錄的值有:
鼠標按下時鼠標光標的位置
復制代碼 代碼如下:
var oldmouse =new pos(0, 0);
鼠標按下時窗口的位置
var oldpos = new pos(0, 0);
鼠標移動時窗口的新的位置
var newpos = new pos(0, 0);
設置窗口的初始位置
復制代碼 代碼如下:
win.style.left = originalpos.x + "px";
win.style.top = originalpos.y + "px";
又是因為浏覽器的差異(IE和非IE),元素綁定事件處理函數的方法不同(IE使用attachEvent,非IE使用addEventListener),為了簡化事件綁定的操作,定義一個事件綁定函數:
復制代碼 代碼如下:
function bind(ev, func) {
if(isIE) {
header.attachEvent("on" + ev, func);
} else {
header.addEventListener(ev, func, false);
}
}
在做好這些工作後,就可以開始處理鼠標事件了。
在這個程序中,只希望鼠標左鍵拖動窗口,其它鍵都不能,所以需要判斷是否是鼠標左鍵按下。而這個判斷會在幾個函數中都使用到,所以提取出來到一個函數中,通過傳入的參數(鼠標鍵值,即按下了哪個鍵)判斷。在這裡,需要注意浏覽器間的差異:IE中鼠標左鍵的值是1,而非IE中值是0.
復制代碼 代碼如下:
function isLeftButton(btn) {
if(isIE) {
if(btn == 1)
return true;
else
return false;
} else {
if(btn == 0)
return true;
else
return false;
}
}
拖動動作是在按下鼠標左鍵後移動來完成的。把這個動作分享開來,即是鼠標先觸發了按下動作(mousedown),然後觸發了移動動作(mousemove)。為了判斷是否是真的在拖動還是只是鼠標從窗口上經過,設置一個變量來記錄鼠標按下的狀態:
var mousedown = false;
由於CSS中存在的兼容性問題,這裡使用js來控制鼠標懸停在窗口標題欄上面的時候的顏色變化。
懸浮
復制代碼 代碼如下:
function over(e){
header.style.backgroundColor = "#5d5d5d";
}
離開
復制代碼 代碼如下:
function out(e) {
header.style.backgroundColor = "#4d4d4d";
// 有時候鼠標會在未松開的情況下離開窗口,
// 此時通過觸發鼠標的松開事件來使窗口脫離鼠標的控制
up(e);
}
按下
在按下事件中,需要先判斷是否按下的是鼠標的左鍵;
若是才記錄鼠標和窗口此時的位置,否則不記錄。
復制代碼 代碼如下:
function down(e) {
e = e || event;
if(!isLeftButton(e.button))
return;
mousedown = true;
oldmouse.x = e.clientX;
oldmouse.y = e.clientY;
oldpos.x = parseInt(win.style.left.replace("px", ""));
oldpos.y = parseInt(win.style.top.replace("px", ""));
}
松開
復制代碼 代碼如下:
function up(e) {
if(!isLeftButton(e.button))
return;
mousedown = false;
}
移動
這裡就涉及到鼠標的兩個事件:
按下和移動。當且僅當鼠標左鍵按下時,移動動作才有效。
窗口的新位置,是由鼠標在拖動狀態下的移動距離(X和Y的距離)決定的。即:
新的鼠標位置送去按下左鍵時記錄下的位置,得到一個距離,然後將窗口的位置加上鼠標移動的距離得到窗口的新位置。
復制代碼 代碼如下:
function move(e) {
if(!isLeftButton(e.button))
return;
if(mousedown) {
e =e || event;
newpos.x = e.clientX - oldmouse.x;
newpos.y = e.clientY - oldmouse.y
win.style.left = (oldpos.x + newpos.x) + "px";
win.style.top = (oldpos.y + newpos.y) + "px";
}
}
事件處理都寫好了,最後來給元素綁定上吧,阿門!
復制代碼 代碼如下:
bind("mouseover", over);
bind("mouseenter", over);
bind("mouseout", out);
bind("mouseleave", out);
bind("blur", out);
bind("mousedown", down);
bind("mouseup", up);
bind("mousemove", move);
不過在FF中的拖動有問題,只能第一次正常拖動,後面就有點亂了!