转载请注明:TheViperhttp://www.cnblogs.com/TheViper
当页面中有很多滚动条,它们相互嵌套,很不好看,这时就会模拟滚动条,并给这个滚动条好看的样式,使得页面美观。
模拟滚动条很多时候是去用jquery插件,然后写几行代码就搞定了。不过随着mvvm的快速发展,很多时候都懒得用jquery了,这就是本文的动机,本屌力求用简单的不依赖jquery只依赖mvvm(avalon) api的代码,完成一个简易的滚动条。
要求:
1.鼠标滚轮可以让滚动条工作,界面滚动
2.鼠标可以拖动滚动条并让界面滚动
3.页面resize时,滚动条根据页面尺寸变化,仍然可以工作
效果:
很显然,这个组件是基于拖动drag的,本屌又不想重新写,就只有改下ui框架的drag了,这里改的是easy js ui的drag组件。用easy js是因为注释比较多,代码简洁。
本屌把easy js ui的drag组件里的相应方法换成avalon api里的方法,删掉PRototype里的方法及冗余代码
1 define('drag',['avalon-min'],function(avalon){ 2 function getBoundary(container, target) { 3 var borderTopWidth = 0, borderRightWidth = 0, borderBottomWidth = 0, borderLeftWidth = 0, cOffset = avalon(container) 4 .offset(), cOffsetTop = cOffset.top, cOffsetLeft = cOffset.left, tOffset = avalon(target) 5 .offset(); 6 borderTopWidth = parseFloat(avalon.CSS(container,'borderTopWidth')); 7 borderRightWidth = parseFloat(avalon.css(container,'borderRightWidth')); 8 borderBottomWidth = parseFloat(avalon.css(container,'borderBottomWidth')); 9 borderLeftWidth = parseFloat(avalon.css(container,'borderLeftWidth')); 10 cOffsetTop = cOffsetTop - tOffset.top + parseFloat(avalon(target).css('top')); 11 cOffsetLeft = cOffsetLeft - tOffset.left + parseFloat(avalon(target).css('left')); 12 return { 13 top : cOffsetTop + borderTopWidth, 14 right : cOffsetLeft + avalon(container).outerWidth() - avalon(target).outerWidth() 15 - borderRightWidth, 16 left : cOffsetLeft + borderLeftWidth, 17 bottom : cOffsetTop + avalon(container).outerHeight() - avalon(target).outerHeight() 18 - borderBottomWidth 19 }; 20 } 21 var drag = function(target, options) { 22 var defaults = { 23 axis:null, 24 container:null, 25 handle:null, 26 ondragmove:null 27 }; 28 var o =avalon.mix(defaults,options), 29 doc = target.ownerDocument, 30 win = doc.defaultView || doc.parentWindow, 31 originHandle=target, 32 isIE =!-[1,], 33 handle = isIE ? target :doc, 34 container = o.container ?o.container: null, 35 count = 0, 36 drag = this, 37 axis = o.axis, 38 isMove = false, 39 boundary, zIndex, originalX, originalY, 40 clearSelect = 'getSelection' in win ? function(){ 41 win.getSelection().removeAllRanges(); 42 } : function(){ 43 try{ 44 doc.selection.empty(); 45 } 46 catch( e ){}; 47 }, 48 down = function( e ){ 49 o.isDown = true; 50 var newTarget = target, 51 left, top, offset; 52 o.width = avalon(target).outerWidth(); 53 o.height = avalon(target).outerHeight(); 54 o.handle = handle; 55 left = avalon(newTarget).css( 'left' ); 56 top = avalon(newTarget).css( 'top' ); 57 offset = avalon(newTarget).offset(); 58 drag.left = left = parseInt( left ); 59 drag.top = top = parseInt( top ); 60 drag.offsetLeft = offset.left; 61 drag.offsetTop = offset.top; 62 originalX = e.pageX - left; 63 originalY = e.pageY - top; 64 if( (!boundary && container)){ 65 boundary = getBoundary(container, newTarget ); 66 } 67 if( axis ){ 68 if( axis === 'x' ){ 69 originalY = false; 70 } 71 else if( axis === 'y' ){ 72 originalX = false; 73 } 74 } 75 if( isIE ){ 76 handle.setCapture(); 77 } 78 avalon.bind(handle,'mousemove',move); 79 avalon.bind(handle,'mouseup',up); 80 if( isIE ){ 81 avalon.bind(handle,'losecapture',up); 82 } 83 e.stopPropagation(); 84 e.preventDefault(); 85 }, 86 move = function( e ){ 87 if( !o.isDown ){ 88 return; 89 } 90 count++; 91 if( count % 2 === 0 ){ 92 return; 93 } 94 var currentX = e.pageX, 95 currentY = e.pageY, 96 style = target.style, 97 x, y, left, right, top, bottom; 98 clearSelect(); 99 isMove = true;100 if( originalX ){101 x = currentX - originalX;102 if( boundary ){103 left = boundary.left;104 right = boundary.right;105 x = x < left ? left : 106 x > right ? right :107 x;108 } 109 drag.left = x;110 drag.offsetLeft = currentX - e.offsetX;111 style.left = x + 'px';112 }113 if( originalY ){114 y = currentY - originalY;115 if( boundary ){116 top = boundary.top;117 bottom = boundary.bottom;118 y = y < top ? top : 119 y > bottom ? bottom :120 y;121 } 122 drag.top = y;123 drag.offsetTop = currentY - e.offsetY;124 style.top = y + 'px';125 }126 o.ondragmove.call(this,drag);127 e.stopPropagation(); 128 },129 up = function( e ){130 o.isDown = false;131 if( isIE ){132 avalon.unbind(handle,'losecapture' );133 }134 avalon.unbind( handle,'mousemove');135 avalon.unbind( handle,'mouseup');136 if( isIE ){137 handle.releaseCapture();138 }139 e.stopPropagation(); 140 }; 141 avalon(originHandle).css( 'cursor', 'pointer' );142 avalon.bind( originHandle,'mousedown', down );143 drag.refresh=function(){144 boundary=getBoundary(container,target);145 }; 146 };147 return drag;148 });View Code
另外在最后暴露的drag上加了一个refresh()方法,作用是在resize时,需要更新滚动条可以拖动的范围。这个方法在scrollbar的更新视图中会用到。
drag.refresh=function(){ boundary=getBoundary(container,target); };
还有在滚动条拖动过程move中,添加一个钩子,允许从外面添加一个监听函数,拖动时会触发监听函数,并传入drag参数。
o.ondragmove.call(this,drag);
然后是scrollbar.js
1 define('scrollbar',['avalon-min','drag'],function(avalon,drag){ 2 function scrollbar(wrap,scrollbar,height_per_scroll){//容器,滚动条,每次滚轮移动的距离 3 this.scroll_height=0;//滚动条高度 4 this.dragger=null;//drag组件实例 5 wrap.scrollTop=0; 6 //容器的位置要减去浏览器最外面的默认滚动条垂直方向位置 7 var self=this,wrap_top=avalon(wrap).offset().top-avalon(document).scrollTop(); 8 function ondragmove(drag){//drag组件拖动时的监听函数,更新容器视图 9 wrap.scrollTop=(parseFloat(scrollbar.style.top)-wrap_top)*10 (wrap.scrollHeight -wrap.clientHeight)/(wrap.clientHeight-self.scroll_height);11 };12 function setScrollPosition(o) {//更新滚动条位置13 scrollbar.style.top =o.scrollTop*wrap.clientHeight/wrap.scrollHeight+wrap_top+ 'px';14 }15 function inti_events(){16
新闻热点
疑难解答