This article example shares the specific code of js to implement a custom scroll bar component for your reference. The specific content is as follows Functional requirements: 1. Create menu content according to the data structure and display it on the page; Let’s take a look at the effect: Default state: Click the menu, and a scroll bar will appear after the content overflows; Drag the scroll bar with the mouse, and the entire content scrolls up: analyze:
The code is attached below: HTML structure, simulate data, create outer container: <!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:"Audi",category:[ {name:"Audi A3",href:""}, {name:"Audi A4L",category:[ {name:"Audi A4L-1",href:""} ]}, {name:"Audi Q3",href:""}, {name:"Audi Q5L",href:""}, {name:"Audi Q2L",href:""}, {name:"Audi Q7 (Imported)",href:""}, {name:"Audi Q8 (Imported)",href:""}, {name:"Audi Q7 New Energy",href:""}, ]}, {name:"Alfa Romeo",category:[ {name:"Stelvio (Imported)",href:""}, {name:"Giulia (Imported)",href:""}, ]} ]}, {name:"B",category:[ {name:"Mercedes-Benz",category:[ {name:"Mercedes-Benz C-Class",href:""}, {name:"Mercedes-Benz E-Class",href:""}, {name:"Mercedes-Benz GLA-Class",href:""}, {name:"Mercedes-Benz GLC-Class",href:""}, {name:"Mercedes-Benz A-Class",href:""}, {name:"Mercedes-Benz E-Class (Imported)",href:""}, {name:"Mercedes-Benz A-Class (Imported)",href:""}, {name:"Mercedes-Benz B-Class (Imported)",href:""}, {name:"威霆",href:""}, {name:"Mercedes-Benz V-Class",href:""}, ]}, {name:"BMW",category:[ {name:"BMW 5 Series",href:""}, {name:"BMW 1 Series",href:""}, {name:"BMW X1",href:""}, {name:"BMW X5 (Imported)",href:""}, {name:"BMW X6 (Imported)",href:""}, ]}, {name:"Honda",category:[ {name:"Jingrui",href:""}, {name:"Civic",href:""}, {name:"Honda CR-V",href:""}, {name:"Honda XR-V",href:""}, {name:"Honda UR-V",href:""}, {name:"Elysion",href:""}, {name:"Xiangyu",href:""}, {name:"INSPIRE",href:""}, {name:"Lingpai",href:""}, {name:"Accord",href:""}, {name:"Binzhi",href:""}, ]}, {name:"Buick",category:[ {name:"Kailue",href:""}, {name:"英朗",href:""}, {name:"威朗",href:""}, {name:"YueLang",href:""}, {name:"Regal",href:""}, {name:"LaCrosse",href:""}, {name:"Angkola",href:""}, {name:"Envision",href:""}, {name:"Buick GL8",href:""}, {name:"Buick GL6",href:""}, {name:"VELITE",href:""}, ]} ]} ] var container; init(); function init(){ createMenu(arr); createScrollBar(); } function createMenu(arr){ //Create a menu let menu=new Menu(arr); //Create the outermost container 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(){ //Create a scroll bar let scrollBar=new ScrollBar(container); scrollBar.appendTo(container); } </script> </body> </html> Menu.js file, creates the folding menu content according to the data: 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; //Create the outermost ul container let ul=Utils.createE("ul",{ listStyle:"none", padding:"0px", margin:"0px", width:"235px", height:"360px", color:"#333", fontSize:"14px", userSelect: "none", position:"absolute" }); //Create li list this.createMenu(_list,ul); //ul listens for click events ul.addEventListener("click",e=>this.clickHandler(e)); //ul listens for scroll wheel events, Firefox uses DOMMouseScroll, other browsers use mousewheel ul.addEventListener("mousewheel",e=>this.mouseWheelHandler(e)); ul.addEventListener("DOMMouseScroll",e=>this.mouseWheelHandler(e)); return ul; } appendTo(parent){ Utils.appendTo(this.elem,parent); } //Create a first level menu 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, //Control the first level menu from being folded by clicking}) let span = Utils.createE("span",{ marginLeft:"14px", fontSize:"18px" },{ textContent:_list[i].name }) Utils.appendTo(span,li); Utils.appendTo(li,parent); //Create a submenu. The third parameter controls whether the submenu is displayed this.createSubMenu(_list[i].category,li,0); } } //Create a submenu createSubMenu(_subList,_parent,_index){ //If there is no submenu, jump out 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){ //If the current menu has no submenu, create a tag to jump 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{ //If the current menu has a submenu, create a span tag 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 the current menu has no submenu, skip the following execution if(!_subList[i].category) continue; //Use the submenu of the current menu as a parameter and perform recursion this.createSubMenu(_subList[i].category,subLi,1); } Utils.appendTo(subUl,_parent); } clickHandler(e){ //If the current click is not a li tag or span, jump out directly 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; //If there is no submenu under the current click Li, jump out directly if(targ.children.length<=1) return; //If the current click is the first-level menu, jump out directly if(targ.data===1) return; //Control the display and hide of ul under the currently clicked Li if(!targ.bool) targ.lastElementChild.style.display="block"; else targ.lastElementChild.style.display="none"; targ.bool=!targ.bool; //Change the content of the span tag this.changeSpan(targ); //Throw an event to change the height of the scroll bar 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){ //Stop event bubbling e.stopPropagation(); //Firefox checks e.detail. When e.detail<0, it means the wheel is down and the page is up. let tag=e.detail,wheelDir; //Other browsers judge e.deltaY. When e.deltaY<0, it means the scroll wheel is down and the page is up if(tag===0) tag=e.deltaY; if(tag>0){ //The wheel scrolls down and the page goes up wheelDir="down"; }else{ wheelDir="up"; } //Throw an event and pass the scroll wheel direction let evt = new Event(Menu.MOUSE_WHEEL_EVENT); evt.wheelDirection=wheelDir; this.elem.dispatchEvent(evt); } } ScrollBar.js file, create a scroll bar, and operate the scroll bar: 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(); //Listen to the menu's click event and dynamically change the scroll bar's height document.addEventListener(ScrollBar.SET_BAR_HEIGHT,()=>this.setBarHeight()); //ul menu listens for wheel events this.menuUl.addEventListener(Menu.MOUSE_WHEEL_EVENT,e=>this.mouseWheelHandler(e)); } createElem() { if (this.elem) return this.elem; //Create the outer container of the scroll bar 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; //Create scroll bar this.bar = Utils.createE("div", { width: "100%", position: "absolute", left: "0px", top: "0px", borderRadius: "10px", backgroundColor: "rgba(255,0,0,.5)" }) //Set the scroll bar hover state style this.bar.addEventListener("mouseenter",e=>this.setMouseStateHandler(e)); this.bar.addEventListener("mouseleave",e=>this.setMouseStateHandler(e)); //Set the height of the scroll bar this.setBarHeight(); //Listen for mouse drag events this.mouseHand = e => this.mouseHandler(e); this.bar.addEventListener("mousedown", this.mouseHand); Utils.appendTo(this.bar, _parent); } setBarHeight() { //The height of the outer parent container this.conHeight = this.container.clientHeight; //The actual content height this.menuHeight = this.container.firstElementChild.scrollHeight; //If the actual content height is less than the parent container height, the scroll bar is hidden if (this.conHeight >= this.menuHeight) this.bar.style.display = "none"; else this.bar.style.display = "block"; //Calculate the height of the scroll bar let h = Math.floor(this.conHeight / this.menuHeight * this.conHeight); this.bar.style.height = h + "px"; } setMouseStateHandler(e){ //Set the scroll bar hover state style 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": //Note: In the result returned by getBoundingClientRect(), width and height both include border var rect = this.container.getBoundingClientRect(); this.barTop = e.clientY - rect.y - this.y; //Scroll bar movement this.barMove(); break; case "mouseup": document.removeEventListener("mousemove", this.mouseHand); document.removeEventListener("mouseup", this.mouseHand); break; } } mouseWheelHandler(e){ //Roller event if(e.wheelDirection==="down"){ //Scroll down, menu content goes up this.barTop+=this.wheelSpeed; }else{ this.barTop-=this.wheelSpeed; } //Scroll bar movement 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"; //Menu content scrolling this.menuMove(); } menuMove(){ //Calculate the scroll height of the content let menuTop=this.barTop/(this.conHeight-this.bar.offsetHeight)*(this.menuHeight-this.conHeight); this.menuUl.style.top=-menuTop+"px"; } } Utils.js file is a toolkit: 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(/[AZ]/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); } } } The above is the full content of this article. I hope it will be helpful for everyone’s study. I also hope that everyone will support 123WORDPRESS.COM. You may also be interested in:
|
>>: Linux concurrent execution is simple, just do it this way
Recently, when I was learning Django, I needed to...
Table of contents 1. Purpose 2. Grammar 3. Practi...
Table of contents 1. Basic types 2. Object Type 2...
The DIV floating effect (fixed position) is imple...
I have done some research on "embedding non-...
When we learn HTML, the image tag <img> int...
Table of contents Scene Introduction Plugin Imple...
Since I returned the Mac, my original laptop has ...
Web design is both a science and an art. Web desi...
Its function is to set a global style. Then your s...
Sttty is a common command for changing and printi...
Preface: After the automation is written, it need...
aforementioned This article is very short~ The ma...
<!--[if IE 6]> Only IE6 can recognize <![...
1 Get the installation resource package mysql-8.0...