原生JavaScript實現滾動條
沒事找事,明明overflow:scroll|auto就可以,只是難看點(實際上css也能設置)。只當練習寫拖拽、監聽事件、位置檢測了。
原理是對滑動條塊進行監聽,按下滑鼠按鍵後,監聽滑鼠移動,然後根據滑動條塊移動的百分比算出滾動區域的滾動程度,用marginLeft進行滾動。具體的寫在註釋里。
整體弄成了一個對象,防止各種亂七八糟的數據污染全局變數。另外,對象內部調用的函數也都寫到了對象構造函數的裡面,由於對象作用域鏈的原理,外部無法進行調用,防止不小心在外部調用。
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <title>Blank Page for Rich Text Editing</title> 5 <meta http-equiv="content-type" name="author" content="Fujihara No Kokukiyo" /> 6 <meta charset="utf-8" /> 7 </head> 8 <style rel="stylesheet" type="text/css"> 9 .outer{width:500px;border:1px solid black;overflow:hidden;margin:50px 0 0 100px;} 10 .test_div{width:1200px;background-image:linear-gradient(90deg,lightcoral 0%,lightgreen 50%,lightblue 100%);height:150px;} 11 .slider_bar,.slider_block{ border-radius:5px;} 12 .slider_bar{position:relative;width:80%;margin:5px auto 5px auto;background-color:lightgreen;height:5px;} 13 .slider_block{width:20px;height:5px;background-color:grey;cursor:pointer;position:absolute;} 14 </style> 15 <script type="text/javascript"> 16 window.onload=function(){ 17 /** 18 * 滑動條對象構造函數, 19 * 內含其他功能性函數,利用函數作用域鏈的原理,防止自己隨意調用 20 * 相容:firefox、opera、chrome 21 * ie沒試,然而顯然不相容舊版本ie(8及之前),因為舊版本ie添加事件監聽函數的方法不同。如若要相容ie,還需要添加其他函數 22 * js生成的滑動條類名為slider_bar、滑動塊類型為slider_block,可用css樣式自己設置大小、顏色等。 23 * 滑動條左右padding未限制滑動條界限,如若需要限制,須在計算部分進行細小修改,加算padding,此處略去。 24 * 25 * @param {DOMElement} slider_content 被滾動的元素(不是被滾動元素的父元素) 26 */ 27 function Slider(slider_content){ 28 //slider_instance為對象本身(在事件處理函數中會進行訪問,而事件處理函數中的this對象已被註入為event.currentTarget,因此預先存儲) 29 var slider_instance=this; 30 //this.slider_content為被滾動的元素 31 this.slider_content=slider_content; 32 //this.outer為被滾動元素的父元素 33 this.outer=slider_content.parentNode; 34 //創建滑動條 35 this.slider_bar=createSliderBar(); 36 //創建滑動條塊 37 this.slider_block=createSliderBlock(); 38 //拼裝 39 this.slider_bar.appendChild(this.slider_block); 40 this.outer.appendChild(this.slider_bar); 41 //被滾動元素可被滾動的總寬度 42 this.slider_content_width=this.slider_content.offsetWidth-this.outer.clientWidth; 43 //滑動條塊可滑動的總寬度 44 this.slider_bar_width=this.slider_bar.clientWidth-this.slider_block.offsetWidth; 45 //被滾動元素的左邊距(相對父元素) 46 this.slider_content_left=0; 47 //滾動塊的左邊距(相對父元素) 48 this.slider_block_left=0; 49 //滑動條的左邊距(相對視口) 50 this.slider_bar_pageLeft=getPageLeft(this.slider_bar); 51 //滑動條塊添加滑鼠壓鍵事件 52 this.slider_block.addEventListener("mousedown",mousedownHandler,false); 53 //離開父元素後取消滑鼠移動事件 54 this.outer.addEventListener("mouseleave",mouseupHandler,false); 55 //滑鼠彈鍵時取消滑鼠移動事件 56 this.outer.addEventListener("mouseup",mouseupHandler,false); 57 /** 58 * 創建滑動條 59 */ 60 function createSliderBar(){ 61 var slider_bar=document.createElement("div"); 62 slider_bar.className="slider_bar"; 63 return slider_bar; 64 } 65 /** 66 * 創建滑動條塊 67 */ 68 function createSliderBlock(){ 69 var slider_block=document.createElement("div"); 70 slider_block.className="slider_block"; 71 return slider_block 72 } 73 /** 74 * 滑鼠按下事件處理 75 */ 76 function mousedownHandler(event){ 77 //計算滑鼠相對滑動塊的左邊距,進而在滑鼠移動事件處理函數中使用 78 //滑鼠相對滑動塊左邊距=滑鼠相對視口左邊距-滑動塊相對視口左邊距 79 slider_instance.mouseLeft=event.clientX-getPageLeft(this); 80 console.log(getPageLeft(this)); 81 slider_instance.outer.addEventListener("mousemove",mousemoveHandler,false); 82 } 83 /** 84 * 滑鼠移動事件處理 85 */ 86 function mousemoveHandler(event){ 87 //計算出應當設置的滑動塊左邊距(相對於父容器) 88 //滑動塊相對於滑動條左邊距=滑鼠相對於視口左邊距-滑動條相對於視口左邊距-滑鼠相對於滑動塊左邊距 89 var blockLeft=event.clientX-slider_instance.slider_bar_pageLeft-slider_instance.mouseLeft; 90 //如若滑動塊相對於父容器左邊距大於滑動塊可移動寬度或小於0,表示過界;設置為左右界限值 91 if(blockLeft>slider_instance.slider_bar_width){ 92 blockLeft=slider_instance.slider_bar_width 93 }else if(blockLeft<0){ 94 blockLeft=0; 95 } 96 //設置滑動塊的新位置 97 slider_instance.slider_block.style.left=blockLeft+"px"; 98 //按照滾動塊已滾動的百分比,設置被滾動元素的marginLeft(負值),進而讓其滾動起來 99 //被滾動元素的左margin=-(滑動塊相對於滑動條左邊距/可滑動最大寬度*可滾動元素的最大寬度) 100 slider_instance.slider_content.style.marginLeft="-"+(blockLeft/slider_instance.slider_bar_width*slider_instance.slider_content_width)+"px"; 101 } 102 /** 103 * 滑鼠鍵彈起事件處理 104 */ 105 function mouseupHandler(event){ 106 slider_instance.outer.removeEventListener("mousemove",mousemoveHandler,false); 107 } 108 /** 109 * 獲得元素的視口左邊距 110 */ 111 function getPageLeft(el){ 112 var result=el.offsetLeft; 113 var parent=el.offsetParent; 114 while(parent!==null){ 115 result+=parent.offsetLeft; 116 parent=parent.offsetParent; 117 } 118 return result; 119 } 120 } 121 //用test_div元素進行展示 122 new Slider(document.getElementsByClassName("test_div")[0]); 123 124 } 125 </script> 126 <body> 127 <div class="outer"> 128 <div class="test_div"></div> 129 </div> 130 </body> 131 </html>