原生js實(shí)現(xiàn)模擬滾動(dòng)條
當(dāng)頁(yè)面中有很多滾動(dòng)條,它們相互嵌套,很不好看,這時(shí)就會(huì)模擬滾動(dòng)條,并給這個(gè)滾動(dòng)條好看的樣式,使得頁(yè)面美觀。
模擬滾動(dòng)條很多時(shí)候是去用jquery插件,然后寫幾行代碼就搞定了。不過(guò)隨著mvvm的快速發(fā)展,很多時(shí)候都懶得用jquery了,這就是本文的動(dòng)機(jī),力求用簡(jiǎn)單的不依賴jquery只依賴mvvm(avalon) api的代碼,完成一個(gè)簡(jiǎn)易的滾動(dòng)條。
要求:
1.鼠標(biāo)滾輪可以讓滾動(dòng)條工作,界面滾動(dòng)
2.鼠標(biāo)可以拖動(dòng)滾動(dòng)條并讓界面滾動(dòng)
3.頁(yè)面resize時(shí),滾動(dòng)條根據(jù)頁(yè)面尺寸變化,仍然可以工作
效果:
很顯然,這個(gè)組件是基于拖動(dòng)drag的,本人又不想重新寫,就只有改下ui框架的drag了,這里改的是easy js ui的drag組件。用easy js是因?yàn)樽⑨尡容^多,代碼簡(jiǎn)潔。
本人把easy js ui的drag組件里的相應(yīng)方法換成avalon api里的方法,刪掉prototype里的方法及冗余代碼
define('drag',['avalon-min'],function(avalon){ function getBoundary(container, target) { var borderTopWidth = 0, borderRightWidth = 0, borderBottomWidth = 0, borderLeftWidth = 0, cOffset = avalon(container) .offset(), cOffsetTop = cOffset.top, cOffsetLeft = cOffset.left, tOffset = avalon(target) .offset(); borderTopWidth = parseFloat(avalon.css(container,'borderTopWidth')); borderRightWidth = parseFloat(avalon.css(container,'borderRightWidth')); borderBottomWidth = parseFloat(avalon.css(container,'borderBottomWidth')); borderLeftWidth = parseFloat(avalon.css(container,'borderLeftWidth')); cOffsetTop = cOffsetTop - tOffset.top + parseFloat(avalon(target).css('top')); cOffsetLeft = cOffsetLeft - tOffset.left + parseFloat(avalon(target).css('left')); return { top : cOffsetTop + borderTopWidth, right : cOffsetLeft + avalon(container).outerWidth() - avalon(target).outerWidth() - borderRightWidth, left : cOffsetLeft + borderLeftWidth, bottom : cOffsetTop + avalon(container).outerHeight() - avalon(target).outerHeight() - borderBottomWidth }; } var drag = function(target, options) { var defaults = { axis:null, container:null, handle:null, ondragmove:null }; var o =avalon.mix(defaults,options), doc = target.ownerDocument, win = doc.defaultView || doc.parentWindow, originHandle=target, isIE =!-[1,], handle = isIE ? target :doc, container = o.container ?o.container: null, count = 0, drag = this, axis = o.axis, isMove = false, boundary, zIndex, originalX, originalY, clearSelect = 'getSelection' in win ? function(){ win.getSelection().removeAllRanges(); } : function(){ try{ doc.selection.empty(); } catch( e ){}; }, down = function( e ){ o.isDown = true; var newTarget = target, left, top, offset; o.width = avalon(target).outerWidth(); o.height = avalon(target).outerHeight(); o.handle = handle; left = avalon(newTarget).css( 'left' ); top = avalon(newTarget).css( 'top' ); offset = avalon(newTarget).offset(); drag.left = left = parseInt( left ); drag.top = top = parseInt( top ); drag.offsetLeft = offset.left; drag.offsetTop = offset.top; originalX = e.pageX - left; originalY = e.pageY - top; if( (!boundary && container)){ boundary = getBoundary(container, newTarget ); } if( axis ){ if( axis === 'x' ){ originalY = false; } else if( axis === 'y' ){ originalX = false; } } if( isIE ){ handle.setCapture(); } avalon.bind(handle,'mousemove',move); avalon.bind(handle,'mouseup',up); if( isIE ){ avalon.bind(handle,'losecapture',up); } e.stopPropagation(); e.preventDefault(); }, move = function( e ){ if( !o.isDown ){ return; } count++; if( count % 2 === 0 ){ return; } var currentX = e.pageX, currentY = e.pageY, style = target.style, x, y, left, right, top, bottom; clearSelect(); isMove = true; if( originalX ){ x = currentX - originalX; if( boundary ){ left = boundary.left; right = boundary.right; x = x < left ? left : x > right ? right : x; } drag.left = x; drag.offsetLeft = currentX - e.offsetX; style.left = x + 'px'; } if( originalY ){ y = currentY - originalY; if( boundary ){ top = boundary.top; bottom = boundary.bottom; y = y < top ? top : y > bottom ? bottom : y; } drag.top = y; drag.offsetTop = currentY - e.offsetY; style.top = y + 'px'; } o.ondragmove.call(this,drag); e.stopPropagation(); }, up = function( e ){ o.isDown = false; if( isIE ){ avalon.unbind(handle,'losecapture' ); } avalon.unbind( handle,'mousemove'); avalon.unbind( handle,'mouseup'); if( isIE ){ handle.releaseCapture(); } e.stopPropagation(); }; avalon(originHandle).css( 'cursor', 'pointer' ); avalon.bind( originHandle,'mousedown', down ); drag.refresh=function(){ boundary=getBoundary(container,target); }; }; return drag; });
另外在最后暴露的drag上加了一個(gè)refresh()方法,作用是在resize時(shí),需要更新滾動(dòng)條可以拖動(dòng)的范圍。這個(gè)方法在scrollbar的更新視圖中會(huì)用到。
drag.refresh=function(){ boundary=getBoundary(container,target); };
還有在滾動(dòng)條拖動(dòng)過(guò)程move中,添加一個(gè)鉤子,允許從外面添加一個(gè)監(jiān)聽函數(shù),拖動(dòng)時(shí)會(huì)觸發(fā)監(jiān)聽函數(shù),并傳入drag參數(shù)。
o.ondragmove.call(this,drag);
然后是scrollbar.js
define('scrollbar',['avalon-min','drag'],function(avalon,drag){ function scrollbar(wrap,scrollbar,height_per_scroll){//容器,滾動(dòng)條,每次滾輪移動(dòng)的距離 this.scroll_height=0;//滾動(dòng)條高度 this.dragger=null;//drag組件實(shí)例 wrap.scrollTop=0; //容器的位置要減去瀏覽器最外面的默認(rèn)滾動(dòng)條垂直方向位置 var self=this,wrap_top=avalon(wrap).offset().top-avalon(document).scrollTop(); function ondragmove(drag){//drag組件拖動(dòng)時(shí)的監(jiān)聽函數(shù),更新容器視圖 wrap.scrollTop=(parseFloat(scrollbar.style.top)-wrap_top)* (wrap.scrollHeight -wrap.clientHeight)/(wrap.clientHeight-self.scroll_height); }; function setScrollPosition(o) {//更新滾動(dòng)條位置 scrollbar.style.top =o.scrollTop*wrap.clientHeight/wrap.scrollHeight+wrap_top+ 'px'; } function inti_events(){ avalon.bind(wrap,'mousewheel',function(e){ if(e.wheelDelta < 0) wrap.scrollTop+=height_per_scroll; else wrap.scrollTop-=height_per_scroll; setScrollPosition(wrap); e.preventDefault(); }); self.dragger=new drag(scrollbar,{container:wrap,axis:'y',ondragmove:ondragmove}); window.onresize=function(){ self.refresh_views(); self.dragger.refresh(); }; } this.refresh_views=function(){//更新組件所有部分視圖,并暴露供外部調(diào)用 //容器高度這里設(shè)置成瀏覽器可視部分-容器垂直方向位置,沒有考慮容器有border,padding,margin.可根據(jù)相應(yīng)場(chǎng)景修改 wrap.style.height=document.documentElement.clientHeight-wrap_top+'px'; self.scroll_height=wrap.clientHeight*wrap.clientHeight/wrap.scrollHeight; //容器高度等于滾動(dòng)條高度,隱藏滾動(dòng)條 if(self.scroll_height==wrap.clientHeight) scrollbar.style.display='none'; else scrollbar.style.display='block'; scrollbar.style.height=self.scroll_height+'px'; setScrollPosition(wrap); } function init(){ self.refresh_views(); inti_events(); } init(); } return scrollbar; });
可以看到,在resize時(shí),調(diào)用了drag組件的refresh方法,更新滾動(dòng)條可以拖動(dòng)的范圍。這里暴露了refresh_views()方法,以應(yīng)對(duì)外部需要手動(dòng)更新視圖的情況。比如,聊天分組的折疊和展開。
這樣就完成了簡(jiǎn)易滾動(dòng)條。代碼很簡(jiǎn)單,如果出問(wèn)題需要fix bug或定制的話,也很容易。
以上所述上就是本文的全部?jī)?nèi)容了,希望大家能夠喜歡。
- 基于JavaScript實(shí)現(xiàn)自定義滾動(dòng)條
- JavaScript自定義瀏覽器滾動(dòng)條兼容IE、 火狐和chrome
- JavaScript 輪播圖和自定義滾動(dòng)條配合鼠標(biāo)滾輪分享代碼貼
- javascript自定義滾動(dòng)條實(shí)現(xiàn)代碼
- JS實(shí)現(xiàn)的頁(yè)面自定義滾動(dòng)條效果
- 原生JavaScript實(shí)現(xiàn)滾動(dòng)條效果
- js/jquery獲取瀏覽器窗口可視區(qū)域高度和寬度以及滾動(dòng)條高度實(shí)現(xiàn)代碼
- 判斷滾動(dòng)條到底部的JS代碼
- js滾動(dòng)條回到頂部的代碼
- 原生js封裝自定義滾動(dòng)條
相關(guān)文章
鼠標(biāo)劃過(guò)實(shí)現(xiàn)延遲加載并隱藏層的js代碼
鼠標(biāo)劃過(guò)延遲加載隱藏層的效果,想必大家都有見到過(guò)吧,在本文將為大家詳細(xì)介紹下使用js是如何實(shí)現(xiàn)的,感興趣的朋友可以參考下2013-10-10深入了解Hybrid App技術(shù)的相關(guān)知識(shí)
這篇文章主要介紹了深入了解Hybrid App技術(shù)的相關(guān)知識(shí),Hybrid App(混合模式移動(dòng)應(yīng)用)是指介于web-app、native-app這兩者之間的app,兼具" Native App良好用戶交互體驗(yàn)的優(yōu)勢(shì) "和" Web App跨平臺(tái)開發(fā)的優(yōu)勢(shì) ",需要的朋友可以參考下2019-07-07OpenLayers3實(shí)現(xiàn)地圖顯示功能
這篇文章主要為大家詳細(xì)介紹了OpenLayers3實(shí)現(xiàn)地圖顯示功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-09-09JS比較兩個(gè)時(shí)間大小的簡(jiǎn)單示例代碼
本篇文章主要介紹了JS比較兩個(gè)時(shí)間大小的簡(jiǎn)單示例代碼。需要的朋友可以過(guò)來(lái)參考下,希望對(duì)大家有所幫助2013-12-12js實(shí)現(xiàn)鼠標(biāo)跟隨運(yùn)動(dòng)效果
這篇文章主要為大家詳細(xì)介紹了js實(shí)現(xiàn)鼠標(biāo)跟隨運(yùn)動(dòng)效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-09-09js setTimeout()函數(shù)介紹及應(yīng)用以倒計(jì)時(shí)為例
setTimeout() 方法用于在指定的毫秒數(shù)后調(diào)用函數(shù)或計(jì)算表達(dá)式,下面有個(gè)倒計(jì)時(shí)的示例,需要的朋友可以學(xué)習(xí)下2013-12-12JavaScript股票的動(dòng)態(tài)買賣規(guī)劃實(shí)例分析下篇
這篇文章主要介紹了JavaScript對(duì)于動(dòng)態(tài)規(guī)劃解決股票問(wèn)題的真題例舉講解。文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2022-08-08