亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

原生js實(shí)現(xiàn)自定義滾動(dòng)條組件

 更新時(shí)間:2021年08月19日 10:45:38   作者:蒲公英芽  
這篇文章主要為大家詳細(xì)介紹了原生js實(shí)現(xiàn)自定義滾動(dòng)條組件的開發(fā),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下

本文實(shí)例為大家分享了js實(shí)現(xiàn)自定義滾動(dòng)條組件的具體代碼,供大家參考,具體內(nèi)容如下

功能需求:

1、按照數(shù)據(jù)結(jié)構(gòu)創(chuàng)建菜單內(nèi)容,顯示在頁面中;
2、點(diǎn)擊菜單后,顯示對(duì)應(yīng)的下級(jí)菜單內(nèi)容,如果整體內(nèi)容溢出,則出現(xiàn)滾動(dòng)條;
3、滾動(dòng)條的高度要隨著整體內(nèi)容高度的改變而改變。
4、鼠標(biāo)拖動(dòng)滾動(dòng)條,整體內(nèi)容要隨著向上滾動(dòng)。
5、當(dāng)鼠標(biāo)滾動(dòng)時(shí),滾動(dòng)條和整體內(nèi)容也要相應(yīng)滾動(dòng)。

來看一下效果:

默認(rèn)狀態(tài):

點(diǎn)擊菜單,內(nèi)容溢出后,出現(xiàn)滾動(dòng)條;

鼠標(biāo)拖動(dòng)滾動(dòng)條,整體內(nèi)容隨著向上滾動(dòng):

分析:

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

下面附上代碼:

html結(jié)構(gòu),模擬數(shù)據(jù),創(chuàng)建外層容器:

<!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(進(jìn)口)",href:""},
   {name:"奧迪Q8(進(jìn)口)",href:""},
   {name:"奧迪Q7新能源",href:""},
  ]},
  {name:"阿爾法-羅密歐",category:[
   {name:"Stelvio(進(jìn)口)",href:""},
   {name:"Giulia(進(jìn)口)",href:""},
  ]}
  ]},
  {name:"B",category:[
  {name:"奔馳",category:[
   {name:"奔馳C級(jí)",href:""},
   {name:"奔馳E級(jí)",href:""},
   {name:"奔馳GLA級(jí)",href:""},
   {name:"奔馳GLC級(jí)",href:""},
   {name:"奔馳A級(jí)",href:""},
   {name:"奔馳E級(jí)(進(jìn)口)",href:""},
   {name:"奔馳A級(jí)(進(jìn)口)",href:""},
   {name:"奔馳B級(jí)(進(jìn)口)",href:""},
   {name:"威霆",href:""},
   {name:"奔馳V級(jí)",href:""},
  ]},
  {name:"寶馬",category:[
   {name:"寶馬5系",href:""},
   {name:"寶馬1系",href:""},
   {name:"寶馬X1",href:""},
   {name:"寶馬X5(進(jìn)口)",href:""},
   {name:"寶馬X6(進(jìn)口)",href:""},
  ]},
  {name:"本田",category:[
   {name:"競?cè)?,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){
  //創(chuàng)建菜單
  let menu=new Menu(arr);
  //創(chuàng)建最外層容器
  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(){
  //創(chuàng)建滾動(dòng)條
  let scrollBar=new ScrollBar(container);
  scrollBar.appendTo(container);
 }
 </script>
</body>
</html>

Menu.js文件,根據(jù)數(shù)據(jù)創(chuàng)建折疊菜單內(nèi)容:

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;
 //創(chuàng)建最外層ul容器
 let ul=Utils.createE("ul",{
  listStyle:"none",
  padding:"0px",
  margin:"0px",
  width:"235px",
  height:"360px",
  color:"#333",
  fontSize:"14px",
  userSelect: "none",
  position:"absolute"
 });
 //創(chuàng)建li列表
 this.createMenu(_list,ul);
 //ul監(jiān)聽點(diǎn)擊事件
 ul.addEventListener("click",e=>this.clickHandler(e));
 //ul監(jiān)聽滾輪事件,火狐使用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);
 }
 //創(chuàng)建一級(jí)菜單
 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,//控制一級(jí)菜單不能點(diǎn)擊折疊
  })
  let span=Utils.createE("span",{
  marginLeft:"14px",
  fontSize:"18px"
  },{
  textContent:_list[i].name
  })
  Utils.appendTo(span,li);
  Utils.appendTo(li,parent);
  //創(chuàng)建子菜單,第三個(gè)參數(shù)控制子菜單是否顯示
  this.createSubMenu(_list[i].category,li,0);
 }
 }
 //創(chuàng)建子菜單
 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){
  //如果當(dāng)前菜單沒有子菜單,則創(chuàng)建a標(biāo)簽,進(jìn)行跳轉(zhuǎn)
  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{
  //如果當(dāng)前菜單有子菜單,創(chuàng)建span標(biāo)簽
  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);
  //如果當(dāng)前菜單沒有子菜單,則跳過下面的執(zhí)行
  if(!_subList[i].category) continue;
  //將當(dāng)前菜單的子菜單作為參數(shù),進(jìn)行遞歸
  this.createSubMenu(_subList[i].category,subLi,1);
 }
 Utils.appendTo(subUl,_parent);
 }
 clickHandler(e){
 //如果當(dāng)前點(diǎn)擊的不是li標(biāo)簽或者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;
 //如果當(dāng)前點(diǎn)擊Li下面沒有子菜單,直接跳出
 if(targ.children.length<=1) return;
 //如果當(dāng)前點(diǎn)擊的是一級(jí)菜單,直接跳出
 if(targ.data===1) return;
 //控制當(dāng)前點(diǎn)擊的Li下的ul顯示隱藏
 if(!targ.bool) targ.lastElementChild.style.display="block";
 else targ.lastElementChild.style.display="none";
 targ.bool=!targ.bool;
 //改變span標(biāo)簽的內(nèi)容
 this.changeSpan(targ);
 //拋發(fā)事件,改變滾動(dòng)條的高度
 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時(shí),表示滾輪往下,頁面往上
 let tag=e.detail,wheelDir;
 //其他瀏覽器判斷e.deltaY,e.deltaY<0時(shí),表示滾輪往下,頁面往上
 if(tag===0) tag=e.deltaY;

 if(tag>0){
  //滾輪往下滾動(dòng),頁面往上走
  wheelDir="down";
 }else{
  wheelDir="up";
 }
 //拋發(fā)事件,將滾輪方向傳遞過去
 let evt=new Event(Menu.MOUSE_WHEEL_EVENT);
 evt.wheelDirection=wheelDir;
 this.elem.dispatchEvent(evt);
 }
}

ScrollBar.js文件,創(chuàng)建滾動(dòng)條,對(duì)滾動(dòng)條進(jìn)行操作:

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();
 //偵聽菜單的點(diǎn)擊事件,動(dòng)態(tài)改變滾動(dòng)條的高度
 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;
 //創(chuàng)建滾動(dòng)條的外層容器
 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;
 //創(chuàng)建滾動(dòng)條
 this.bar = Utils.createE("div", {
  width: "100%",
  position: "absolute",
  left: "0px",
  top: "0px",
  borderRadius: "10px",
  backgroundColor: "rgba(255,0,0,.5)"
 })
 //設(shè)置滾動(dòng)條hover狀態(tài)的樣式
 this.bar.addEventListener("mouseenter",e=>this.setMouseStateHandler(e));
 this.bar.addEventListener("mouseleave",e=>this.setMouseStateHandler(e));
 //設(shè)置滾動(dòng)條的高度
 this.setBarHeight();
 //偵聽鼠標(biāo)拖動(dòng)事件
 this.mouseHand = e => this.mouseHandler(e);
 this.bar.addEventListener("mousedown", this.mouseHand);
 Utils.appendTo(this.bar, _parent);
 }
 setBarHeight() {
 //外層父容器的高度
 this.conHeight = this.container.clientHeight;
 //實(shí)際內(nèi)容的高度
 this.menuHeight = this.container.firstElementChild.scrollHeight;
 //如果實(shí)際內(nèi)容的高度小于父容器的高度,滾動(dòng)條隱藏
 if (this.conHeight >= this.menuHeight) this.bar.style.display = "none";
 else this.bar.style.display = "block";
 //計(jì)算滾動(dòng)條的高度
 let h = Math.floor(this.conHeight / this.menuHeight * this.conHeight);
 this.bar.style.height = h + "px";
 }
 setMouseStateHandler(e){
 //設(shè)置滾動(dòng)條hover狀態(tài)的樣式
 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()返回的結(jié)果中,width height 都是包含border的
  var rect = this.container.getBoundingClientRect();
  this.barTop = e.clientY - rect.y - this.y;
  //滾動(dòng)條移動(dòng)
  this.barMove();
  break;
  case "mouseup":
  document.removeEventListener("mousemove", this.mouseHand);
  document.removeEventListener("mouseup", this.mouseHand);
  break;
 }
 }
 mouseWheelHandler(e){
 //滾輪事件
 if(e.wheelDirection==="down"){
  //滾動(dòng)往下,菜單內(nèi)容往上
  this.barTop+=this.wheelSpeed;
 }else{
  this.barTop-=this.wheelSpeed;
 }
 //滾動(dòng)條移動(dòng)
 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";
 //菜單內(nèi)容滾動(dòng)
 this.menuMove();
 }
 menuMove(){
 //計(jì)算內(nèi)容的滾動(dòng)高度
 let menuTop=this.barTop/(this.conHeight-this.bar.offsetHeight)*(this.menuHeight-this.conHeight);
 this.menuUl.style.top=-menuTop+"px";
 }
}

Utils.js文件,是一個(gè)工具包:

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);
 }
 }
}

以上就是本文的全部內(nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • 一文搞懂JavaScript中原型與原型鏈

    一文搞懂JavaScript中原型與原型鏈

    js中的原型與原型鏈應(yīng)該是老生常談的話題了,在前端面試中基本都是必問的一個(gè)問題,但是很多人還是稀里糊涂的,只知道其表層含義。本文將帶大家深入了解JavaScript中的原型與原型鏈,感興趣的可以學(xué)習(xí)一下
    2022-10-10
  • 淺析Javascript的自動(dòng)分號(hào)插入(ASI)機(jī)制

    淺析Javascript的自動(dòng)分號(hào)插入(ASI)機(jī)制

    我們大家都知道在寫java和c時(shí),必須要在語句后加分號(hào),否則編譯通不過。而js不同,存在自動(dòng)分好插入機(jī)制,下文簡稱ASI。它會(huì)給源代碼的 token 流自動(dòng)插入分號(hào)。下面這篇文章我們就來談?wù)凧avascript的自動(dòng)分號(hào)插入(ASI)機(jī)制。
    2016-09-09
  • layui 數(shù)據(jù)表格 點(diǎn)擊分頁按鈕 監(jiān)聽事件的實(shí)例

    layui 數(shù)據(jù)表格 點(diǎn)擊分頁按鈕 監(jiān)聽事件的實(shí)例

    今天小編就為大家分享一篇layui 數(shù)據(jù)表格 點(diǎn)擊分頁按鈕 監(jiān)聽事件的實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2019-09-09
  • 驗(yàn)證碼按回車不變解決方法

    驗(yàn)證碼按回車不變解決方法

    驗(yàn)證碼圖片顯示的時(shí)候,后面沒有加隨機(jī)參數(shù)導(dǎo)致在ie里面,怎么按回車都不變,顯示的是同樣的驗(yàn)證碼,火狐沒有發(fā)現(xiàn)這個(gè)bug
    2013-03-03
  • JS動(dòng)態(tài)顯示表格上下frame的方法

    JS動(dòng)態(tài)顯示表格上下frame的方法

    這篇文章主要介紹了JS動(dòng)態(tài)顯示表格上下frame的方法,涉及javascript中顯示表格frame的技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下
    2015-03-03
  • 關(guān)于JavaScript的gzip靜態(tài)壓縮方法

    關(guān)于JavaScript的gzip靜態(tài)壓縮方法

    關(guān)于JavaScript的gzip靜態(tài)壓縮方法...
    2007-01-01
  • Array.prototype.concat不是通用方法反駁[譯]

    Array.prototype.concat不是通用方法反駁[譯]

    ECMAScript 5.1規(guī)范中指出,數(shù)組方法concat是通用的(generic).本文反駁了這一結(jié)論,因?yàn)閷?shí)際上并不是這樣的
    2012-09-09
  • JS實(shí)現(xiàn)的base64加密、md5加密及sha1加密詳解

    JS實(shí)現(xiàn)的base64加密、md5加密及sha1加密詳解

    這篇文章主要介紹了JS實(shí)現(xiàn)的base64加密、md5加密及sha1加密的方法,結(jié)合實(shí)例形式詳細(xì)分析了JavaScript各種常見加密方法與實(shí)現(xiàn)技巧,需要的朋友可以參考下
    2016-04-04
  • js實(shí)現(xiàn)模糊匹配功能

    js實(shí)現(xiàn)模糊匹配功能

    這篇文章主要為大家詳細(xì)介紹了js實(shí)現(xiàn)模糊匹配功能,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-02-02
  • JavaScript調(diào)試工具匯總

    JavaScript調(diào)試工具匯總

    這篇文章主要介紹了7款基于桌面和WEB的JavaScript調(diào)試工具,更有效地處理動(dòng)態(tài)類型使應(yīng)用程序更符合編碼標(biāo)準(zhǔn),不管你是新學(xué)習(xí)javascript的菜鳥還是業(yè)界大神,都非常的有用。
    2014-12-12

最新評(píng)論