寫了個js自制滾動條,首先,先看一下demo(點擊這里) 先
有兩個demo,右邊那個黑色那個,是我一開始寫的比較膚淺的代碼:
var scrollself=(function(){ var scrollblock, //滾動塊 scrollcontent, //被滾動的內容 scrollbar, //滾動條 scrollpanel, //滾動內容的滾動區域 cdistance, //滾動內容要滾動的距離 bdistance, //滾動塊要滾動的距離 minuTop, //滾動條頭尾剩下的空白 cTop, //滾動內容的top startY=0, //滾動動作開始初鼠標的位置 bTop=0, //滾動動作開始初滾動塊的top isDrag=false; //是否拉動滾動塊 function prevent(e){ if(e.preventDefault){ e.preventDefault(); } if(e.stopPropagation){ e.stopPropagation(); } e.cancelBubble=true; e.returnValue=false; } function mouseDown(event){ isDrag=true; event=event||window.event; startY=event.clientY; bTop=scrollblock.offsetTop; cTop=scrollcontent.offsetTop; // prevent(event); } function mouseMove(event){ if(isDrag){ event=event||window.event; var newbTop=event.clientY-startY+bTop, newcTop=cTop-(event.clientY-startY)/bdistance*cdistance; if(newbTop<minuTop){ newbTop=minuTop; newcTop=0; }else{ if(newbTop>bdistance+minuTop){ newcTop=-cdistance; newbTop=bdistance+minuTop; } } scrollblock.style.top=newbTop+'px'; scrollcontent.style.top=newcTop+'px'; }else{ isDrag=false; } // prevent(event); } function mouseUp(event){ isDrag=false; // prevent(event); } function addHandler(){ scrollblock.onmousedown=mouseDown; scrollblock.onmousemove=mouseMove; scrollblock.onmouseup=mouseUp; document.onmouseup=mouseUp; } return{ init:function(scrollpanel_id,scrollcontent_id,scrollbar_id,scrollblock_id){ scrollblock=document.getElementById(scrollblock_id); scrollcontent=document.getElementById(scrollcontent_id); scrollbar=document.getElementById(scrollbar_id); scrollpanel=document.getElementById(scrollpanel_id); minuTop=scrollblock.offsetTop; cdistance=scrollcontent.offsetHeight-scrollpanel.offsetHeight; bdistance=scrollbar.offsetHeight-minuTop*2-scrollblock.offsetHeight; enclose(scrollpanel,scrollcontent,scrollbar,scrollblock,bdistance,cdistance,minuTop); addHandler(); } } }()); scrollself.init('scrollpanel2','scrollcontent2','scrollbar2','scrollblock2');
之所以說它膚淺,比較一下兩個demo的滾動效果就知道了,右邊的快速拉動滾動塊時候,體驗效果好差,很卡,而左邊的就流暢多了。
因為很卡,我就又上網看了一下別人的代碼,然后把根據別人的思路把代碼改了一下,就有了左邊那個綠色的那個demo,很明顯,效果好了很多,代碼:
var scroll=(function(){ var scrollblock, //滾動塊 scrollcontent, //被滾動的內容 scrollbar, //滾動條 scrollpanel, //滾動內容的滾動區域 cdistance, //滾動內容要滾動的距離 bdistance, //滾動塊要滾動的距離 minuTop, //滾動條頭尾剩下的空白 cTop, //滾動內容的top startY=0, //滾動動作開始初鼠標的位置 bTop=0; //滾動動作開始初滾動塊的top function mouseDown(event){ event=event||window.event; startY=event.clientY; bTop=scrollblock.offsetTop; cTop=scrollcontent.offsetTop; // if(scrollblock.setCapture){ // scrollblock.onmousemove=doDrag; // scrollblock.onmouseup=stopDrag; // scrollblock.setCapture(); // }else{ // document.addEventListener("mousemove",doDrag,true); // document.addEventListener("mouseup",stopDrag,true); // } document.onmousemove=function(){ doDrag(); } document.onmouseup=function(){ stopDrag(); } document.getElementsByTagName('body')[0].onselectstart=function(){ return false; } } function doDrag(event){ event=event||window.event; var newbTop=event.clientY-startY+bTop, newcTop=cTop-(event.clientY-startY)/bdistance*cdistance; if(newbTop<minuTop){ newbTop=minuTop; newcTop=0; }else if(newbTop>bdistance+minuTop){ newcTop=-cdistance; newbTop=bdistance+minuTop; } scrollblock.style.top=newbTop+'px'; scrollcontent.style.top=newcTop+'px'; } function stopDrag(event){ // if(scrollblock.releaseCapture){ // // scrollblock.onmousemove=doDrag; // // scrollblock.onmouseup=stopDrag; // scrollblock.releaseCapture(); // }else{ // document.removeEventListener("mousemove",doDrag,true); // document.removeEventListener("mouseup",stopDrag,true); // } document.onmousemove=null; document.onmouseup=null; document.getElementsByTagName('body')[0].onselectstart=function(){ return true; }; } return{ init:function(scrollpanel_id,scrollcontent_id,scrollbar_id,scrollblock_id){ scrollblock=document.getElementById(scrollblock_id); scrollcontent=document.getElementById(scrollcontent_id); scrollbar=document.getElementById(scrollbar_id); scrollpanel=document.getElementById(scrollpanel_id); minuTop=scrollblock.offsetTop; cdistance=scrollcontent.offsetHeight-scrollpanel.offsetHeight; bdistance=scrollbar.offsetHeight-minuTop*2-scrollblock.offsetHeight; scrollblock.onmousedown=mouseDown; enclose(scrollpanel,scrollcontent,scrollbar,scrollblock,bdistance,cdistance,minuTop); } } }()); scroll.init('scrollpanel','scrollcontent','scrollbar','scrollblock');
(一開始錯誤的誤解:比較了一下兩個的代碼,其實修改的不多,就有一點很大的不同,流暢的那一個(左邊綠色那一個)多了這個東西——setCapture、releaseCapture。
具體是怎樣的,再研究一下先。
SetCapture()函數的說明為:“該函數在屬於當前線程的指定窗口里設置鼠標捕獲。一旦窗口捕獲了鼠標,所有鼠標輸入都針對該窗口,無論光標是否在窗口的邊界內。同一時刻只能有一個窗口捕獲鼠標。如果鼠標光標在另一個線程創建的窗口上,只有當鼠標鍵按下時系統才將鼠標輸入指向指定的窗口。”
綠色demo不卡是因為SetCapture()函數使得鼠標onmousemove的時候,即使鼠標離開了滾動塊,滾動塊仍可以捕獲得到onmousemove的消息,而黑色demo卡的原因就是因為鼠標離開了滾動塊,就捕獲不了了。)
囧啊,以上灰色部分真是不知所謂的誤解,后來再認真想一下其實沒那么復雜,只要在鼠標點擊滾動塊的時候把mousemove跟mouseup事件注冊到document里就行了,然后mouseup的時候事件解綁掉,所以把代碼給改了,其實沒有setCapture、releaseCapture也行的,而且這兩個東西是針對ie的。。
