JavaScript实现竖向滚动条的一种思路

  • A+
所属分类:Web前端
摘要

设计目标:希望复刻浏览器原生竖向滚动条的功能,并且能做一些个性化配置

设计目标:希望复刻浏览器原生竖向滚动条的功能,并且能做一些个性化配置

测试页面:

 1 <!DOCTYPE html>  2 <html lang="en">  3 <head>  4     <meta charset="UTF-8">  5     <title>Title</title>  6     <script src="MyScrolly.js"></script>  7 </head>  8 <body>  9 <div id="div_allbase" style="width: 800px;height: 600px;background-color: beige;overflow-y: hidden"> 10     <div id="div_outer" style="width: 700px;height: 500px;background-color: cornflowerblue;overflow-y: auto"> 11         <div id="div_inner1" style="width: 600px;height: 300px;background-color: darkseagreen"> 12 111111111111111111111111111111111111111111111111111111111111111 13         </div> 14         <div id="div_inner2" style="width: 600px;height: 300px;margin-top: 50px;background-color: darkseagreen""> 15 222222222222222222222222222222222222222222222222222222222222222 16         </div> 17         <div id="div_inner3" style="width: 600px;height: 300px;margin-top: 50px;background-color: darkseagreen""> 18 333333333333333333333333333333333333333333333333333333333333333 19         </div> 20     </div> 21 </div> 22 </body> 23 <script> 24     var myScroll=new MyScrolly(document.getElementById("div_outer")//要添加滚动条的元素 25         ,{parentelem:document.getElementById("div_allbase")})//配置参数 26     myScroll.func_count(myScroll);//在innerHTML发生变化或onresize之后重新计算dragbar的长度
    //使用这种方式可以为页面中的多个元素配置不同的滚动条样式
27 </script> 28 </html>

代码实现:

  1 function MyScrolly(elem,obj_p)   2 {   3     if(elem)   4     {   5         obj_p=obj_p||{};   6         this.elem=elem;   7         this.func_render=obj_p.func_render||MyScrolly.defaultRender;//滚动条的dom结构   8         this.func_count=obj_p.func_count||MyScrolly.countChildren;//在页面发生变化时滚动条的变化方式   9         this.func_render(elem,this);  10         this.parentelem=obj_p.parentelem||elem;//支持拖拽、释放、禁止选择等动作的外围元素范围,默认设置为document可能效果更好  11         //this.clientY0=this.elem.clientY;//没有用到  12         this.last_clientY=-1;  13         //elem.onload  14         var that=this;  15         //使用页面观察器观察dom变化!!<-兼容性如何??<-html5,并且会导致this被替换为MutationObserver对象,并且不好控制调用条件  16         // var MutationObserver=window.MutationObserver||window.WebKitMutationObserver||window.MozMutationObserver;  17         // //var mo=new MutationObserver(that.countChildren);  18         // var mo=new MutationObserver(function(records){  19         //     that.func_count(that);  20         // });  21         // this.mo=mo;  22         // var option={  23         //     childList:true,  24         //     subtree:true,  25         // }  26         //mo.observe(this.elem,option);  27   28         this.div2.onpointerdown=function (event) {//按下scrollbar  29             that.picked=true;  30             that.last_clientY=event.clientY;//取相对定位的参考点  31             that.parentelem.onselectstart=function(event){//防止在上下滑动时选中div中的文本  32                 event.returnValue=false;  33                 return false;  34             }  35         }  36         this.parentelem.onpointerup=function (event) {  37             that.picked=false;  38             that.parentelem.onselectstart=null;  39             //that.parentelem.onmousewheel=null;  40         }  41         this.parentelem.onpointerleave=function (event) {  42             that.picked=false;  43             that.parentelem.onselectstart=null;  44             that.parentelem.onmousewheel=null;  45         }  46         this.parentelem.onpointermove=function (event) {//拖动效果在div_allbase范围内均有效  47             if(that.picked==true&&(that.last_clientY>=0))  48             {  49                 //event.preventDefault();//阻止默认的行为发生  50   51                 var int_clientY=event.clientY-that.last_clientY;//因为比较难定位elem的初始位置(也许elem自身会发生移动或变形),这里使用相对变化量  52                 that.last_clientY=event.clientY;  53                 var top_div2=parseInt(that.div2.style.top);//滑块上端到滑轨上端的距离,关于div2等属性的含义见defaultRender方法  54                 var int1=top_div2+int_clientY;  55                 if((that.outer_height-that.height_scrollbar)<int1)  56                 {//如果过于靠下  57                     int1=that.outer_height-that.height_scrollbar  58                 }  59                 if(int1<0)  60                 {//如果过于靠上  61                     int1=0  62                 }  63   64                 // if((that.outer_height-that.height_scrollbar)>=(top_div2+int_clientY)&&((top_div2+int_clientY)>=0))  65                 // {  66                     that.div2.style.top=int1+"px";//移动滑块  67                     var int2=(int1)/(that.outer_height/that.inner_height)  68                     that.elem.scrollTop=int2;//滚动元素内容  69                     that.div1.style.top=int2+"px";//移动滑轨  70                     //console.log(that.elem.scrollTop);  71                // }  72   73   74             }  75         }  76         //this.parentelem.onclick=function(event){  77         this.parentelem.onmouseenter=function(event){//鼠标滚轮,这里没有兼容火狐  78             that.parentelem.onmousewheel=function(event){  79                 if(that.last_clientY<0)  80                 {  81                     that.last_clientY=0;  82                 }  83                 if((that.last_clientY>=0))  84                 {  85                     var int_clientY=-event.wheelDelta;  86                     var top_div2=parseInt(that.div2.style.top);  87                     var int1=top_div2+int_clientY;  88                     if((that.outer_height-that.height_scrollbar)<int1)  89                     {  90                         int1=that.outer_height-that.height_scrollbar  91                     }  92                     if(int1<0)  93                     {  94                         int1=0  95                     }  96   97                         that.div2.style.top=int1+"px";  98                         var int2=(int1)/(that.outer_height/that.inner_height)  99                         that.elem.scrollTop=int2; 100                         that.div1.style.top=int2+"px"; 101                         //console.log(that.elem.scrollTop); 102  103                 } 104             } 105         } 106  107     } 108     else { 109         return false; 110     } 111  112  113 } 114 //MyScrolly.prototype 115 //计算容器内部组件的实际高度,并就此调整滚动条显示效果 116 //MyScrolly.prototype.countChildren=function(records){ 117 MyScrolly.countChildren=function(that){ 118     //this=that; 119     var arr=that.elem.childNodes;//如果使用MutationObserver,则这里的this是MutationObserver对象!! 120     var len=arr.length; 121     var sum_height=0; 122     // for(var i=0;i<len;i++)//假设除了滚动条之外的所有元素都是纵向排列的!!《-这里需要递归排列!!?? 123     // {累加元素内部children的高度 124     //     var obj=arr[i]; 125     //     if(obj.className!="div_myscroll1") 126     //     { 127     //         var int=obj.offsetHeight; 128     //         if(int)//有些textnode的高度可能是undefined!! 129     //         { 130     //             sum_height+=int; 131     //         } 132     // 133     //     } 134     // } 135     //考虑到margin,换一种测量思路 136     for(var i=len-1;i>0;i--) 137     { 138         var obj=arr[i]; 139         if(obj.className!="div_myscroll1") 140         { 141             var int=obj.offsetHeight; 142             if(int)//有些textnode的高度可能是undefined!! 143             { 144                 sum_height+=int; 145                 sum_height+=obj.offsetTop; 146                 break; 147             } 148  149         } 150     } 151     that.inner_height=sum_height;//元素内容高度 152     that.outer_height=that.elem.offsetHeight;//元素本身高度 153     console.log("重新测量高度"+that.outer_height+"/"+that.inner_height); 154     that.div2.style.top="0px";//滑块复位 155     that.elem.scrollTop=0; 156     that.clientY0=0; 157     that.picked=false; 158     that.last_clientY=-1;//这里还应该加上取消监听的代码 159     if(that.inner_height<=that.outer_height)//如果不需要显示滚动条 160     { 161         that.div1.style.display="none"; 162     } 163     else { 164         that.div1.style.display="block"; 165         var int=that.outer_height*(that.outer_height/that.inner_height); 166         that.height_scrollbar=int; 167         that.div2.style.height=int+"px"; 168     } 169 } 170 //默认的滚动条样式,也可以在这里使用图片等自定义样式 171 MyScrolly.defaultRender=function(elem,that) 172 { 173     elem.style.position="relative"; 174     elem.style.overflowX="hidden"; 175     elem.style.overflowY="hidden";//取消浏览器自带的滚动条 176     var div1=document.createElement("div");//滑轨 177     div1.className="div_myscroll1"; 178     div1.style.width="10px"; 179     div1.style.backgroundColor="rgb(245,245,245)"; 180     div1.style.position="absolute"; 181     div1.style.right="0px"; 182     div1.style.top="0px"; 183     div1.style.height="100%"; 184     div1.style.zIndex=elem.style.zIndex+10; 185     div1.style.display="none"; 186     that.div1=div1; 187     var div2=document.createElement("div");//滑块 188     div2.className="div_myscroll2"; 189     div2.style.width="10px"; 190     div2.style.backgroundColor="rgb(226,226,226)"; 191     div2.style.position="absolute"; 192     div2.style.right="0px"; 193     div2.style.top="0px"; 194     //div1.style.height="100%"; 195     div2.style.zIndex=elem.style.zIndex+20; 196     that.div2=div2; 197     div1.appendChild(div2); 198     elem.appendChild(div1); 199 }