激情久久久_欧美视频区_成人av免费_不卡视频一二三区_欧美精品在欧美一区二区少妇_欧美一区二区三区的

服務器之家:專注于服務器技術及軟件下載分享
分類導航

node.js|vue.js|jquery|angularjs|React|json|js教程|

服務器之家 - 編程語言 - JavaScript - js教程 - 原生js實現自定義滾動條組件

原生js實現自定義滾動條組件

2022-01-05 17:06蒲公英芽 js教程

這篇文章主要為大家詳細介紹了原生js實現自定義滾動條組件的開發,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下

本文實例為大家分享了js實現自定義滾動條組件的具體代碼,供大家參考,具體內容如下

功能需求:

1、按照數據結構創建菜單內容,顯示在頁面中;
2、點擊菜單后,顯示對應的下級菜單內容,如果整體內容溢出,則出現滾動條;
3、滾動條的高度要隨著整體內容高度的改變而改變。
4、鼠標拖動滾動條,整體內容要隨著向上滾動。
5、當鼠標滾動時,滾動條和整體內容也要相應滾動。

來看一下效果:

默認狀態:

原生js實現自定義滾動條組件

點擊菜單,內容溢出后,出現滾動條;

原生js實現自定義滾動條組件

鼠標拖動滾動條,整體內容隨著向上滾動:

原生js實現自定義滾動條組件

分析:

  • 這個案例中包括折疊菜單和滾動條兩個組件 ,所以可以分開來寫,然后整合到一起。
  • 折疊菜單中要考慮多級菜單出現的情況,使用遞歸來做,數據的結構一定要統一,方便對數據進行處理。
  • 滾動條的創建中,有兩個比例等式,一是滾動條的高度/外層div高度=外層div高度/整體內容高度;二是滾動條的位置/(外層div高度-滾動條高度)=內容的scrollTop/(整體內容的高度-外層div高度)
  • 當點擊折疊菜單后,需要相應地設置滾動條的高度。折疊菜單是在Menu.js文件中,滾動條的設置是在ScrollBar.js文件中,需要進行拋發、監聽事件。
  • 監聽菜單鼠標滾動的事件,當鼠標滾動時,判斷滾輪方向,設置滾動條和內容的 top 值,也需要用到事件的拋發和監聽。

下面附上代碼:

html結構,模擬數據,創建外層容器:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
<!DOCTYPE html>
<html lang="en">
<head>
 <meta charset="UTF-8">
 <meta name="viewport" content="width=device-width, initial-scale=1.0">
 <title>scrollBar</title>
</head>
<body>
 <script type="module">
 import Utils from './js/Utils.js';
 import Menu from './js/Menu.js';
 import ScrollBar from './js/ScrollBar.js';
 var arr=[
  {name:"A",category:[
  {name:"奧迪",category:[
   {name:"奧迪A3",href:""},
   {name:"奧迪A4L",category:[
   {name:"奧迪A4L-1",href:""}
   ]},
   {name:"奧迪Q3",href:""},
   {name:"奧迪Q5L",href:""},
   {name:"奧迪Q2L",href:""},
   {name:"奧迪Q7(進口)",href:""},
   {name:"奧迪Q8(進口)",href:""},
   {name:"奧迪Q7新能源",href:""},
  ]},
  {name:"阿爾法-羅密歐",category:[
   {name:"Stelvio(進口)",href:""},
   {name:"Giulia(進口)",href:""},
  ]}
  ]},
  {name:"B",category:[
  {name:"奔馳",category:[
   {name:"奔馳C級",href:""},
   {name:"奔馳E級",href:""},
   {name:"奔馳GLA級",href:""},
   {name:"奔馳GLC級",href:""},
   {name:"奔馳A級",href:""},
   {name:"奔馳E級(進口)",href:""},
   {name:"奔馳A級(進口)",href:""},
   {name:"奔馳B級(進口)",href:""},
   {name:"威霆",href:""},
   {name:"奔馳V級",href:""},
  ]},
  {name:"寶馬",category:[
   {name:"寶馬5系",href:""},
   {name:"寶馬1系",href:""},
   {name:"寶馬X1",href:""},
   {name:"寶馬X5(進口)",href:""},
   {name:"寶馬X6(進口)",href:""},
  ]},
  {name:"本田",category:[
   {name:"競瑞",href:""},
   {name:"思域",href:""},
   {name:"本田CR-V",href:""},
   {name:"本田XR-V",href:""},
   {name:"本田UR-V",href:""},
   {name:"艾力紳",href:""},
   {name:"享域",href:""},
   {name:"INSPIRE",href:""},
   {name:"凌派",href:""},
   {name:"雅閣",href:""},
   {name:"繽智",href:""},
  ]},
  {name:"別克",category:[
   {name:"凱越",href:""},
   {name:"英朗",href:""},
   {name:"威朗",href:""},
   {name:"閱朗",href:""},
   {name:"君威",href:""},
   {name:"君越",href:""},
   {name:"昂科拉",href:""},
   {name:"昂科威",href:""},
   {name:"別克GL8",href:""},
   {name:"別克GL6",href:""},
   {name:"VELITE",href:""},
  ]}
  ]}
 ]
 var container;
 init();
 function init(){
  createMenu(arr); 
  createScrollBar();
 }
  function createMenu(arr){
  //創建菜單
  let menu=new Menu(arr);
  //創建最外層容器
  container=Utils.createE("div",{
  width:"235px",
  height:"360px",
  border:"1px solid #ccc",
  position:"relative",
  overflow:"hidden"
  })
  menu.appendTo(container);
  Utils.appendTo(container,"body")
 }
 function createScrollBar(){
  //創建滾動條
  let scrollBar=new ScrollBar(container);
  scrollBar.appendTo(container);
 }
 </script>
</body>
</html>

Menu.js文件,根據數據創建折疊菜單內容:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
import Utils from './Utils.js';
export default class Menu{
 static SET_BAR_HEIGHT="set_bar_height";
 static MOUSE_WHEEL_EVENT="mouse_wheel_event";
 constructor(_list){
 this.elem=this.createElem(_list);
 }
 createElem(_list){
 if(this.elem) return this.elem;
 //創建最外層ul容器
 let ul=Utils.createE("ul",{
  listStyle:"none",
  padding:"0px",
  margin:"0px",
  width:"235px",
  height:"360px",
  color:"#333",
  fontSize:"14px",
  userSelect: "none",
  position:"absolute"
 });
 //創建li列表
 this.createMenu(_list,ul);
 //ul監聽點擊事件
 ul.addEventListener("click",e=>this.clickHandler(e));
 //ul監聽滾輪事件,火狐使用DOMMouseScroll,其它瀏覽器使用mousewheel
 ul.addEventListener("mousewheel",e=>this.mouseWheelHandler(e));
 ul.addEventListener("DOMMouseScroll",e=>this.mouseWheelHandler(e));
 return ul;
 }
 appendTo(parent){
 Utils.appendTo(this.elem,parent);
 }
 //創建一級菜單
 createMenu(_list,parent){
 for(let i=0;i<_list.length;i++){
  let li=Utils.createE("li",{
  background:"#f5f5f5",
  borderTop:"1px solid #ddd",
  lineHeight:"32px",
  },{
  data:1,//控制一級菜單不能點擊折疊
  })
  let span=Utils.createE("span",{
  marginLeft:"14px",
  fontSize:"18px"
  },{
  textContent:_list[i].name
  })
  Utils.appendTo(span,li);
  Utils.appendTo(li,parent);
  //創建子菜單,第三個參數控制子菜單是否顯示
  this.createSubMenu(_list[i].category,li,0);
 }
 }
 //創建子菜單
 createSubMenu(_subList,_parent,_index){
 //如果沒有子菜單,則跳出
 if(_subList.length===0) return;
 let subUl=Utils.createE("ul",{
  listStyle:"none",
  background:"#fff",
  padding:"0px",
  margin:"0px",
  fontSize:"14px",
  display:_index===0? "block" : "none"
 })
 for(let i=0;i<_subList.length;i++){
  let subLi=Utils.createE("li",{
  paddingLeft:"40px",
  position:"relative",
  cursor:"pointer"
  })
  if(!_subList[i].category){
  //如果當前菜單沒有子菜單,則創建a標簽,進行跳轉
  let subA=Utils.createE("a",{
   color:"#333",
   textDecoration:"none",
   width:"100%",
   display:"inline-block"
  },{
   textContent:_subList[i].name,
   href:_subList[i].href || "javascript:void(0)",
   target:_subList[i].href ? "_blank" : "_self"
  })
  Utils.appendTo(subA,subLi);
  }else{
  //如果當前菜單有子菜單,創建span標簽
  let subSpan=Utils.createE("span",{
   position:"absolute",
   left:"20px",
   top:"8px",
   border: "1px solid #ccc",
   display: "inline-block",
   width: "10px",
   height: "10px",
   lineHeight:"8px"
  },{
   textContent:_subList[i].category.length>0? "+" : "-"
  })
  subLi.textContent=_subList[i].name;
  Utils.appendTo(subSpan,subLi);
  }
  Utils.appendTo(subLi,subUl);
  //如果當前菜單沒有子菜單,則跳過下面的執行
  if(!_subList[i].category) continue;
  //將當前菜單的子菜單作為參數,進行遞歸
  this.createSubMenu(_subList[i].category,subLi,1);
 }
 Utils.appendTo(subUl,_parent);
 }
 clickHandler(e){
 //如果當前點擊的不是li標簽或者span,直接跳出
 if(e.target.nodeName!=="LI" && e.target.nodeName!=="SPAN") return;
 let targ;
 if(e.target.nodeName==="SPAN") targ=e.target.parentElement;
 else targ=e.target;
 //如果當前點擊Li下面沒有子菜單,直接跳出
 if(targ.children.length<=1) return;
 //如果當前點擊的是一級菜單,直接跳出
 if(targ.data===1) return;
 //控制當前點擊的Li下的ul顯示隱藏
 if(!targ.bool) targ.lastElementChild.style.display="block";
 else targ.lastElementChild.style.display="none";
 targ.bool=!targ.bool;
 //改變span標簽的內容
 this.changeSpan(targ);
 //拋發事件,改變滾動條的高度
 var evt=new Event(Menu.SET_BAR_HEIGHT);
 document.dispatchEvent(evt)
 }
 changeSpan(elem){
 if(elem.lastElementChild.style.display==="block"){
  elem.firstElementChild.textContent="-";
 }else{
  elem.firstElementChild.textContent="+";
 }
 }
 mouseWheelHandler(e){
 //阻止事件冒泡
 e.stopPropagation();
 //火狐瀏覽器判斷e.detail,e.detail<0時,表示滾輪往下,頁面往上
 let tag=e.detail,wheelDir;
 //其他瀏覽器判斷e.deltaY,e.deltaY<0時,表示滾輪往下,頁面往上
 if(tag===0) tag=e.deltaY;
 
 if(tag>0){
  //滾輪往下滾動,頁面往上走
  wheelDir="down";
 }else{
  wheelDir="up";
 }
 //拋發事件,將滾輪方向傳遞過去
 let evt=new Event(Menu.MOUSE_WHEEL_EVENT);
 evt.wheelDirection=wheelDir;
 this.elem.dispatchEvent(evt);
 }
}

ScrollBar.js文件,創建滾動條,對滾動條進行操作:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
import Utils from './Utils.js';
import Menu from './Menu.js';
export default class ScrollBar {
 bar;
 conHeight;
 menuHeight;
 wheelSpeed=6;
 barTop=0;
 static SET_BAR_HEIGHT="set_bar_height";
 constructor(parent) {
 this.container = parent;
 this.menuUl=this.container.firstElementChild;
 this.elem = this.createElem();
 //偵聽菜單的點擊事件,動態改變滾動條的高度
 document.addEventListener(ScrollBar.SET_BAR_HEIGHT,()=>this.setBarHeight());
 //ul菜單偵聽滾輪事件
 this.menuUl.addEventListener(Menu.MOUSE_WHEEL_EVENT,e=>this.mouseWheelHandler(e));
 }
 createElem() {
 if (this.elem) return this.elem;
 //創建滾動條的外層容器
 let div = Utils.createE("div", {
  width: "8px",
  height: "100%",
  position: "absolute",
  right: "0px",
  top: "0px",
 })
 this.createBar(div);
 return div;
 }
 appendTo(parent) {
 Utils.appendTo(this.elem,parent);
 }
 createBar(_parent) {
 if(this.bar) return this.bar;
 //創建滾動條
 this.bar = Utils.createE("div", {
  width: "100%",
  position: "absolute",
  left: "0px",
  top: "0px",
  borderRadius: "10px",
  backgroundColor: "rgba(255,0,0,.5)"
 })
 //設置滾動條hover狀態的樣式
 this.bar.addEventListener("mouseenter",e=>this.setMouseStateHandler(e));
 this.bar.addEventListener("mouseleave",e=>this.setMouseStateHandler(e));
 //設置滾動條的高度
 this.setBarHeight();
 //偵聽鼠標拖動事件
 this.mouseHand = e => this.mouseHandler(e);
 this.bar.addEventListener("mousedown", this.mouseHand);
 Utils.appendTo(this.bar, _parent);
 }
 setBarHeight() {
 //外層父容器的高度
 this.conHeight = this.container.clientHeight;
 //實際內容的高度
 this.menuHeight = this.container.firstElementChild.scrollHeight;
 //如果實際內容的高度小于父容器的高度,滾動條隱藏
 if (this.conHeight >= this.menuHeight) this.bar.style.display = "none";
 else this.bar.style.display = "block";
 //計算滾動條的高度
 let h = Math.floor(this.conHeight / this.menuHeight * this.conHeight);
 this.bar.style.height = h + "px";
 }
 setMouseStateHandler(e){
 //設置滾動條hover狀態的樣式
 if(e.type==="mouseenter"){
  this.bar.style.backgroundColor="rgba(255,0,0,1)";
 }else{
  this.bar.style.backgroundColor="rgba(255,0,0,.5)";
 }
 }
 mouseHandler(e) {
 switch (e.type) {
  case "mousedown":
  e.preventDefault();
  this.y = e.offsetY;
  document.addEventListener("mousemove", this.mouseHand);
  document.addEventListener("mouseup", this.mouseHand);
  break;
  case "mousemove":
  //注意:getBoundingClientRect()返回的結果中,width height 都是包含border的
  var rect = this.container.getBoundingClientRect();
  this.barTop = e.clientY - rect.y - this.y;
  //滾動條移動
  this.barMove();
  break;
  case "mouseup":
  document.removeEventListener("mousemove", this.mouseHand);
  document.removeEventListener("mouseup", this.mouseHand);
  break;
 }
 }
 mouseWheelHandler(e){
 //滾輪事件
 if(e.wheelDirection==="down"){
  //滾動往下,菜單內容往上
  this.barTop+=this.wheelSpeed;
 }else{
  this.barTop-=this.wheelSpeed;
 }
 //滾動條移動
 this.barMove();
 }
 barMove(){
 if (this.barTop < 0) this.barTop = 0;
 if (this.barTop > this.conHeight - this.bar.offsetHeight) this.barTop = this.conHeight - this.bar.offsetHeight;
 this.bar.style.top = this.barTop + "px";
 //菜單內容滾動
 this.menuMove();
 }
 menuMove(){
 //計算內容的滾動高度
 let menuTop=this.barTop/(this.conHeight-this.bar.offsetHeight)*(this.menuHeight-this.conHeight);
 this.menuUl.style.top=-menuTop+"px";
 }
}

Utils.js文件,是一個工具包:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
export default class Utils{
 static createE(elem,style,prep){
 elem=document.createElement(elem);
 if(style) for(let prop in style) elem.style[prop]=style[prop];
 if(prep) for(let prop in prep) elem[prop]=prep[prop];
 return elem;
 }
 static appendTo(elem,parent){
 if (parent.constructor === String) parent = document.querySelector(parent);
 parent.appendChild(elem);
 }
 static randomNum(min,max){
 return Math.floor(Math.random*(max-min)+min);
 }
 static randomColor(alpha){
 alpha=alpha||Math.random().toFixed(1);
 if(isNaN(alpha)) alpha=1;
 if(alpha>1) alpha=1;
 if(alpha<0) alpha=0;
 let col="rgba(";
 for(let i=0;i<3;i++){
  col+=Utils.randomNum(0,256)+",";
 }
 col+=alpha+")";
 return col;
 }
 static insertCss(select,styles){
 if(document.styleSheets.length===0){
  let styleS=Utils.createE("style");
  Utils.appendTo(styleS,document.head);
 }
 let styleSheet=document.styleSheets[document.styleSheets.length-1];
 let str=select+"{";
 for(var prop in styles){
  str+=prop.replace(/[A-Z]/g,function(item){
  return "-"+item.toLocaleLowerCase();
  })+":"+styles[prop]+";";
 }
 str+="}"
 styleSheet.insertRule(str,styleSheet.cssRules.length);
 }
 static getIdElem(elem,obj){
 if(elem.id) obj[elem.id]=elem;
 if(elem.children.length===0) return obj;
 for(let i=0;i<elem.children.length;i++){
  Utils.getIdElem(elem.children[i],obj);
 }
 }
}

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持服務器之家。

原文鏈接:https://blog.csdn.net/charissa2017/article/details/104098404

延伸 · 閱讀

精彩推薦
  • js教程如何使用原生Js實現隨機點名詳解

    如何使用原生Js實現隨機點名詳解

    這篇文章主要給大家介紹了關于如何使用原生Js實現隨機點名的相關資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習...

    CV_Di8092021-12-27
  • js教程JavaScript實現點擊切換驗證碼及校驗

    JavaScript實現點擊切換驗證碼及校驗

    這篇文章主要為大家詳細介紹了JavaScript實現點擊切換驗證碼及校驗,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下...

    棟棟很優秀啊3622021-12-29
  • js教程JS addEventListener()和attachEvent()方法實現注冊事件

    JS addEventListener()和attachEvent()方法實現注冊事件

    這篇文章主要介紹了JS addEventListener()和attachEvent()方法實現注冊事件,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,...

    C語言中文網9572021-12-30
  • js教程基于 Next.js 的 SSR/SSG 方案了解一下?

    基于 Next.js 的 SSR/SSG 方案了解一下?

    服務端渲染(SSR,Server Side Render)與客戶端渲染(CSR,Client Side Render)的核心區分點簡單來說就是完整的 HTML 文檔在服務端還是瀏覽器里組裝完成。...

    DYBOY4492021-12-27
  • js教程基于javascript實現移動端輪播圖效果

    基于javascript實現移動端輪播圖效果

    這篇文章主要為大家詳細介紹了基于javascript實現移動端輪播圖效果,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下...

    A.香辣雞腿堡8982021-12-15
  • js教程JavaScript實現頁面高亮操作提示和蒙板

    JavaScript實現頁面高亮操作提示和蒙板

    這篇文章主要介紹了JavaScript實現頁面高亮操作提示和蒙板,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下...

    stones4zd5792021-12-24
  • js教程利用JS判斷元素是否為數組的方法示例

    利用JS判斷元素是否為數組的方法示例

    這篇文章主要給大家介紹了關于利用JS判斷元素是否為數組的相關資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價...

    Fahrenheitzz10022021-12-29
  • js教程mapboxgl實現帶箭頭軌跡線的代碼

    mapboxgl實現帶箭頭軌跡線的代碼

    這篇文章主要介紹了mapboxgl實現帶箭頭軌跡線的代碼,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下...

    GIS兵器庫9152021-12-27
主站蜘蛛池模板: 日本精品久久久久久草草 | 亚洲一区二区免费 | 一级爱爱 | 一级黄色免费观看视频 | 国产一区在线观看视频 | 亚洲精品久久久久久久久久久 | 国产99久久久久久免费看农村 | 亚洲欧美不卡视频 | 国产一区二区在线免费播放 | 黄色av网站免费看 | 美女在线观看视频一区二区 | 欧美性受ⅹ╳╳╳黑人a性爽 | 艹男人的日日夜夜 | 黄色av网站在线观看 | 视频久久免费 | javhdfreejaⅴhd| 国产成人高清成人av片在线看 | 天天天干夜夜夜操 | 天天干天天透 | 奇米888一区二区三区 | 久久99精品国产99久久6男男 | 久久不射电影网 | 成人午夜精品久久久久久久蜜臀 | 一级黄色片武则天 | 99视频有精品 | 久久久涩 | 最新福利在线 | 97黄色网| 九一看片. | 国产成人高清在线观看 | 免费a观看| 免费国产在线视频 | 久久国产成人精品国产成人亚洲 | 99热99精品 | 国产又白又嫩又紧又爽18p | 污黄视频在线播放 | 国产高潮好爽受不了了夜色 | 久久精品av | 欧洲色阁中文字幕 | 精品国产一区二区三区四 | 中文字幕涩涩久久乱小说 |