1. 程式人生 > >JS實現QQ面板-拖曳效果

JS實現QQ面板-拖曳效果

實現的功能是將整個QQ面板在特定區域點選滑鼠按下移動,面板會隨著游標移動而移動,這可以稱為滑鼠跟隨效果,也叫拖曳效果。

首先是確定HTML結構,定義一個父元素模擬整個QQ面板,設定標題區域用於JS選中進行拖曳。

<div class="loginPanel" id="loginPanel">
    <div id="title"></div>
</div>

CSS樣式,這裡有一個需要注意的地方就是面板會跟隨滑鼠移動,涉及到座標的問題就應該在該元素上設定絕對定位。

.loginPanel {width: 380px;height: 247px;left: 400px;top: 120px;position: absolute;border: 1px solid #ccc;background: #f6f6f6;border-radius: 10px;box-shadow: 0 0 8px #000;}
#title {background-color: #adc;width: 200px;height: 44px;cursor: move;position: absolute;top: 10px;left: 98px;}

JS部分,我們來分析一下來確定完成的思路,第一步首要的就是會想到既然是要在特定 title 區域選中滑鼠按下移動,那麼我們就要來獲取到這個 title 元素,獲取之後呢?想不到了,做一步想一步吧。

window.onload=drag;
function drag(){
  var oTitle=document.getElementById("title");
  oTitle.onmousedown=fnDown;
}

title 元素獲取到之後,是進行滑鼠按下移動的,這就用到了onmousedown事件,將其封裝成一個函式,來具體實現。這裡還是不能忘了滑鼠拖曳效果的原理:面板跟隨游標位置的移動而移動。我們需要用到滑鼠座標,又因為滑鼠事件都是在瀏覽器視窗中的特定位置上發生的。這個位置資訊儲存在實踐的clientX和clinetY屬性中。它們的值表示事件發生時滑鼠指標在視口中的水平和垂直座標,不包括頁面滾動的距離。之前有提過QQ面板元素需要絕對定位,那麼設定它的移動就是設定top / left 值。

function fnDown(){
    var oDrag=document.getElementById('loginPanel');
    document.onmousemove=function(event){
        event = event || window.event;
        oDrag.style.left=event.clientX+"px";
        oDrag.style.top=event.clientY+"px";
    }
}

去瀏覽器中試驗一下,有著很明顯的不舒服的地方,也不能算bug,就是使用者體驗不好,每次按下標題中任一個區域拖動面板,滑鼠總會自動跑到整個面板的左上角。這是因為對整個面板的絕對定位是按照左上角那個點進行定位的,也就是說滑鼠移動到哪裡,最後是面板的左上角跟隨到哪裡。這顯然不是我們想要的,我們需要的是在標題中任一區域按下,滑鼠移動到哪裡,之前按下的地方就出現在哪裡。

我們知道了問題所在,那麼該如何解決呢?之前是因為預設的面板左上角跟隨滑鼠,那我們讓按下的地方跟隨滑鼠不就好了嘛,所有現在就得確定我們在title 區域中按下的位置的座標。通過一幅圖來形象的瞭解。

整個外框就相當於瀏覽器邊框,紅色的點就是我們滑鼠按下的位置,那這個點相對於QQ面板的位置資訊可以通過clientX/Y - offsetLeft/Top 計算得到。這樣的話,之前寫的fnDown函式就不對了呀,修改如下。其中,將滑鼠移動事件封裝成函式。

function fnDown(event){
    event = event || window.event;
    var oDrag=document.getElementById('loginPanel'),
        // 游標按下時游標和麵板之間的距離
        disX=event.clientX-oDrag.offsetLeft,
        disY=event.clientY-oDrag.offsetTop;
    // 移動
    document.onmousemove=function(event){
        event = event || window.event;
        fnMove(event,disX,disY);
    }
}

fnMove函式接受三個引數,事件物件,滑鼠點選下相對於面板的上左距離。我們是知道滑鼠移動後是面板的左上角跟隨滑鼠,現在已經有了滑鼠點選下相對於面板的上左距離的值,那麼就可以在原有的左上角座標增加或減去這個值,這就能夠實現滑鼠在哪裡按下,移動之後就在哪裡出現。表述能力真的欠佳,感覺說的亂繞繞的,還是程式碼清晰。

function fnMove(e,posX,posY){
    var oDrag=document.getElementById('loginPanel'),
        l=e.clientX-posX,
        t=e.clientY-posY,
    oDrag.style.left=l+'px';
    oDrag.style.top=t+'px';
}

以上就很好的解決了之前那個使用者體驗不好的地方。那會不會還存在一些問題?顯而易見,一定會有的。我們拖動面板,有時候在瀏覽器邊界時候會一部分移出可視視窗,這也很糟糕呀,譬如一不小心把關閉按鈕啊、登入按鈕啊、輸入框啊這些部分移除可視視窗,就很不好操作了,還需要使用者再把面板移回來,使用者體驗絕對是不好的。這時就需要我們來設定一個範圍,來規定面板可移動的區域。這個區域很明顯就是可視視窗的大小減去面板的大小,這剩下的區域就是面板能夠盡情移動的範圍了。我們需要在fnMove函式基礎上增添。

function fnMove(e,posX,posY){
    var oDrag=document.getElementById('loginPanel'),
        l=e.clientX-posX,
        t=e.clientY-posY,
        winW=document.documentElement.clientWidth || document.body.clientWidth, //可視視窗的寬
        winH=document.documentElement.clientHeight || document.body.clientHeight,   //可視視窗的高
        maxW=winW-oDrag.offsetWidth, //可移動的範圍的寬
        maxH=winH-oDrag.offsetHeight;   //可移動的範圍的高
    if(l<0){
        l=0;
    }else if(l>maxW){
        l=maxW;
    }
    if(t<0){
        t=10;
    }else if(t>maxH){
        t=maxH;
    }
    oDrag.style.left=l+'px';
    oDrag.style.top=t+'px';
}

現在就完成了滑鼠移動拖曳的效果,滑鼠按下之後就可以拖動面板跟著滑鼠移動,嗯,一直移動不帶停的。我們必須要有一個滑鼠釋放的事件,來停止當前的動作。這就用到了onmouseup事件,這個事件的發生是處於整個文件中的。所謂停止當前的動作就是要解除安裝之前滑鼠移動事件,也要解除安裝當前這個滑鼠釋放事件。當然這是發生在fnDown函式中。

document.onmouseup=function(){
    document.onmousemove=null;
    document.onmouseup=null;
}

就此,完美的實現了拖曳效果。需要注意的是關於瀏覽器中座標的計算。