原生实现滚动条模拟

作者:norion时间:2015年9月7日评论次数:0 条

话说坑爹的产品要求做一个漂亮的滚动条,多次强调系统默认的太丑,你想办法做实现一个漂亮的,正在为难时刻想起了问度娘,搜了下,解决方案挺多的,分为两种一直是css解决方案,但是不兼容IE,另外一种是jquery模拟的,要么文件太大、要么有bug,哎这造的什么孽啊!

找来找去还是没满意的,那还是自己写个吧,尝试用原生造个轮子,其中,有两个难点:

1、处理滚动轴事件

2、拖拽滑块事件

我在想调用这个轮子时,我要这样:

scroll({
    scrollWrap: 'l-scroll'
});

其中,scrollWrap是指定的element,那么滑块呢,我是这样想的,滑块是我在调用后生成的,那么我的html就比较干净不用放置什么滑块的代码,只要指定element就可以实现滚动的功能,所以我的HTML结构是这样的:

<div id="l-scroll">
    <div class="box"></div>
</div>

那么,当我滚动时,就是直接改变这个box在marginTop,当然还有我动态创建的滑块top值了,额最外层的element则设置一个高度然后超过的部分直接隐藏。

我们把这个滚动的过程封装成一个函数:

function fScrll(y){
    oScrollBtn.style.top = y + 'px';  //滑块
    oScrollContent.style.marginTop = - (y/nBtnDiff)*nContentDiff +'px';  //box
}

把处理滚动轴事件也封装一个函数:

function fweel(e){
    var wheelDelta,nDistance,nDistances;
    
    e          = e || window.event;
    wheelDelta = e.wheelDelta || e.detail;
    nDistance  = nBtnDiff*0.1;  //滚动基数
    nDistances = oScrollBtn.offsetTop;

    if( wheelDelta == -120 || wheelDelta == 3 ){
        nDistances = nDistances + nDistance;
        nDistances = nDistances >= nBtnDiff ? nBtnDiff : nDistances;
    }else if( wheelDelta == 120 || wheelDelta == -3 ){
        nDistances = nDistances - nDistance;
        nDistances = nDistances <= 1 ? 0 : nDistances
    }
    
    fScrll( nDistances );
    
    if( nDistances === 0 || nDistances === nBtnDiff ) return true;
    
    tool.setOnselectstart(e);
    return false;
}

不要停,还有滑块拖动的事件也封装一个函数:

function fMove(e){
    var y = tool.getMousePosition(e).positionY - tool.getOffset(oScrollBtnWrap).top - nBtnHeight/2;

    fScrll(y>=nBtnDiff ? nBtnDiff : y<=1 ? 0 : y);
}

其中,比较麻烦的事滚动轴和拖动会触发浏览器选中文字的默认事件,IE和chrome等浏览器处理的方式还一样需要写兼容,找了很多资料才找实现想要的效果,没办法谁叫咱是战斗力只有5的渣渣呢:

setOnselectstart: function(e){
    document.all ? e.returnValue = false : e.preventDefault();
    document.onselectstart = function(){return false;};
}

好了,基本上的要点都写了,估计看的人也觉得晕呼呼,来来来,咱贴完整的代码,丑话说前头,以下代码IE8以下版本没测过:

(function (root, factory) {
	if (typeof define === 'function' && define.amd) {
		define(factory);
	} else if (typeof exports === 'object') {
		module.exports = factory();
	} else {
		root.scroll = factory();
	}
}(this, function (){
	
	'use strict';
	
	var tool = {
			
			/* 获取绝对定位 */
			getOffset: function( node ) {
				var nTop  = 0,
					nLeft = 0;
				
			    //var curtopscroll = 0;
			    if (node.offsetParent) {
			        do {
			        	nTop += node.offsetTop;
			        	nLeft += node.offsetLeft;
			            //curtopscroll += node.offsetParent ? node.offsetParent.scrollTop : 0;
			        } while (node = node.offsetParent);
			    }
			    
		        return {
		        	top: nTop,
		        	left: nLeft
	        	}
			},
			
			/* 获取鼠标位置 */
			getMousePosition: function(e){
				var x,y;
				
				e = e || window.event;
				x = e.pageX || e.clientX + (document.documentElement.scrollLeft || document.body.scrollLeft);
				y = e.pageY || e.clientY + (document.documentElement.scrollTop || document.body.scrollTop);   //具有 DTD 时用 document.documentElement.scrollTop 代替 document.body.scrollTop
				
				return{
					positionX : x,
					positionY : y
				}
			},
			
			/* 获取左边兄弟 */
			getPrevSibling: function(el){
				return el.previousElementSibling ? el.previousElementSibling : el.previousSibling;
			},
			
			/* 设置禁用选中 */
			setOnselectstart: function(e){
				document.all ? e.returnValue = false : e.preventDefault();
				document.onselectstart = function(){return false;};
			}
			
		};
	
	/*var SuperScroll = function(){};
	
	SuperScroll.prototype.init = function(){
		
	};*/
	
	var Scroll = function(options){
		
		var bMove          = false,
			//nSpeed         = options.speed,
			oDoc           = document,
			oScrollWrap    = oDoc.getElementById(options.scrollWrap),
			oScrollBtnWrap = (function(){
								var btnWrap = oDoc.createElement('div'),
									btn     = oDoc.createElement('div');
									
								oScrollWrap.className = 'l-scroll-wrap ' + oScrollWrap.className;
								btnWrap.className     = 'l-scroll-btnWrap';
								btn.className         = 'l-scroll-btn';
								
								btnWrap.appendChild(btn);
								oScrollWrap.appendChild(btnWrap);
								
								return oScrollWrap.lastChild;
							})(),
			oScrollBtn     = oScrollBtnWrap.lastChild,
			oScrollContent = tool.getPrevSibling(oScrollBtnWrap),
			nWrapHeight	   = oScrollWrap.offsetHeight - 2, //border的高度
			nBtnHeight     = oScrollBtn.offsetHeight,
			nBtnDiff       = nWrapHeight - nBtnHeight,
			nContentHeight = oScrollContent.offsetHeight,
			nContentDiff   = nContentHeight - nWrapHeight,
			fScrll         = function(y){
								oScrollBtn.style.top = y + 'px';
								oScrollContent.style.marginTop = - (y/nBtnDiff)*nContentDiff +'px';
							},
			fMove          = function(e){
								var y = tool.getMousePosition(e).positionY - tool.getOffset(oScrollBtnWrap).top - nBtnHeight/2;

								fScrll(y>=nBtnDiff ? nBtnDiff : y<=1 ? 0 : y); 							}, 			fWheel         = function(e){ 								var wheelDelta,nDistance,nDistances; 								 								e          = e || window.event; 								wheelDelta = e.wheelDelta || e.detail; 								nDistance  = nBtnDiff*0.1;  //滚动基数 								nDistances = oScrollBtn.offsetTop; 								if( wheelDelta == -120 || wheelDelta == 3 ){ 									nDistances = nDistances + nDistance; 									nDistances = nDistances >= nBtnDiff ? nBtnDiff : nDistances;
								}else if( wheelDelta == 120 || wheelDelta == -3 ){
									nDistances = nDistances - nDistance;
									nDistances = nDistances <= 1 ? 0 : nDistances 								} 								 								fScrll( nDistances ); 								 								if( nDistances === 0 || nDistances === nBtnDiff ) return true; 								 								tool.setOnselectstart(e); 								return false; 							}; 		 		oScrollContent.className    = 'l-scroll-contentWrap ' + oScrollContent.className; 		oScrollContent.style.width  = (oScrollWrap.offsetWidth - 15) + 'px';  //XXX: 短暂的滚动bug 		oScrollBtnWrap.style.height = nWrapHeight + 'px'; 		 		if(nWrapHeight > nContentHeight){
			oScrollBtnWrap.style.display = 'none';
			return;
		}

		oScrollBtnWrap.onclick = function(e){
			fMove(e);
		}
		
		oScrollBtn.onmousedown = function(e){
			bMove = true;
			e = e || window.event;
			tool.setOnselectstart(e);
		}
		
		oDoc.onmouseup = function(){
			bMove = false;
		}

		oDoc.onmousemove = function(e){
			if(bMove) fMove(e);
		}
		
		oDoc.onmousewheel === undefined ? oScrollWrap.addEventListener('DOMMouseScroll', fWheel, true) : oScrollWrap.onmousewheel = fWheel;

	};
	
	Scroll.prototype.setHeight = function(){
		//待扩展
	};
	
	Scroll.prototype.setWidth = function(){
		//待扩展
	};

	return function(o){
		return o ? new Scroll(o) : {};
	};
	
}));

上一篇: 推荐console.dir打印对象的工具

下一篇:原生实现类似jquery append方法

相关文章

评论

发表评论

电子邮件地址不会被公开。 必填项已用*标注