博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
自己写一个jQuery垂直滚动栏插件(panel)
阅读量:7074 次
发布时间:2019-06-28

本文共 6546 字,大约阅读时间需要 21 分钟。

html中原生的滚动栏比較难看,所以有些站点,会自己实现滚动栏,导航站点hao123在一个側栏中,就自己定义了垂直滚动栏,效果比較好看,截图例如以下:

这个滚动栏,仅仅有在鼠标悬停在这个区域内时才显示,半透明效果,非常节省空间的说~~,说实话,这个效果我非常喜欢。

垂直滚动栏的原理,简单来说:

先起个名字,外层的叫wrapper,内层的叫content。wrapper须要有非static的定位,content须要绝对定位,这样就能够通过调节top值来模拟内容滚动。

详细说一下:

1.wrapper的overflow须要设置为hidden,并在wrapper上监听鼠标滚动事件,依据滚动的速度设置content的top值;

2.给wrapper加入滚动框和滚动栏。滚动栏与滚动框的比例和wrapper和content的高度值的比例相应

3.拖拽滚动栏时,content的top值与滚动栏拖拽的距离成比例,反过来滑动鼠标滚轮的时候。滚动栏也要跟着滚动

滚动栏的拖拽,复用我上一篇文章中的拖拽插件。以上就是大致的原理。

下面是基本的代码,__creator是主体函数。先忽略代码的框架,主要看__creator

/* * panel * 參数:obj{ * 	iWheelStep:鼠标滑轮滚动时步进长度 *	sBoxClassName:滚动框的样式 * 	sBarClassName:滚动栏的样式 * } */$.zUI.addWidget("panel",{	defaults : {			iWheelStep:16,			sBoxClassName:"zUIpanelScrollBox",			sBarClassName:"zUIpanelScrollBar"	},	__creator:function(ele){		var jqThis = $(ele);		//假设是static定位。加上relative定位		if(jqThis.css("position") === "static"){			jqThis.css("position","relative");		}		jqThis.css("overflow","hidden");				//必须有一个唯一的直接子元素,给直接子元素加上绝对定位		var jqChild = jqThis.children(":first");		if(jqChild.length){			jqChild.css({top:0,position:"absolute"});		}else{			return;		}				var opts = jqThis.data($.zUI.panel.sOptsName);		//创建滚动框		var jqScrollBox = $("
"); jqScrollBox.addClass(opts.sBoxClassName); //创建滚动栏 var jqScrollBar= $("
"); jqScrollBar.addClass(opts.sBarClassName); jqScrollBox.appendTo(jqThis); jqScrollBar.appendTo(jqThis); opts.iTop = parseInt(jqScrollBox.css("top")); opts.iWidth = jqScrollBar.width(); opts.iRight = parseInt(jqScrollBox.css("right")); //加入拖拽触发自己定义函数 jqScrollBar.on("draggable.move",function(){ var opts = jqThis.data($.zUI.panel.sOptsName); fnScrollContent(jqScrollBox,jqScrollBar,jqThis,jqChild,opts.iTop,0); }); //事件对象 var oEvent ={ mouseenter:function(){ fnFreshScroll(); jqScrollBox.css("display","block"); jqScrollBar.css("display","block"); }, mouseleave:function(){ jqScrollBox.css("display","none"); jqScrollBar.css("display","none"); } }; var sMouseWheel = "mousewheel"; if(!("onmousewheel" in document)){ sMouseWheel = "DOMMouseScroll"; } oEvent[sMouseWheel] = function(ev){ var opts = jqThis.data($.zUI.panel.sOptsName); var iWheelDelta = 1; ev.preventDefault();//阻止默认事件 ev = ev.originalEvent;//获取原生的event if(ev.wheelDelta){ iWheelDelta = ev.wheelDelta/120; }else{ iWheelDelta = -ev.detail/3; } var iMinTop = jqThis.innerHeight() - jqChild.outerHeight(); //外面比里面高。不须要响应滚动 if(iMinTop>0){ jqChild.css("top",0); return; } var iTop = parseInt(jqChild.css("top")); var iTop = iTop + opts.iWheelStep*iWheelDelta; iTop = iTop > 0 ? 0 : iTop; iTop = iTop < iMinTop ? iMinTop : iTop; jqChild.css("top",iTop); fnScrollContent(jqThis,jqChild,jqScrollBox,jqScrollBar,0,opts.iTop); } //记录加入事件 jqThis.data($.zUI.panel.sEventName,oEvent); //尾随滚动函数 function fnScrollContent(jqWrapper,jqContent,jqFollowWrapper,jqFlollowContent,iOffset1,iOffset2){ var opts = jqThis.data($.zUI.panel.sOptsName); var rate = (parseInt(jqContent.css("top"))-iOffset1)/(jqContent.outerHeight()-jqWrapper.innerHeight())//卷起的比率 var iTop = (jqFlollowContent.outerHeight()-jqFollowWrapper.innerHeight())*rate + iOffset2; jqFlollowContent.css("top",iTop); } //刷新滚动栏 function fnFreshScroll(){ var opts = jqThis.data($.zUI.panel.sOptsName); var iScrollBoxHeight = jqThis.innerHeight()-2*opts.iTop; var iRate = jqThis.innerHeight()/jqChild.outerHeight(); var iScrollBarHeight = iScrollBarHeight = Math.round(iRate*iScrollBoxHeight); //假设比率大于等于1。不须要滚动栏,自然也不须要加入拖拽事件 if(iRate >= 1){ jqScrollBox.css("height",0); jqScrollBar.css("height",0); return; } jqScrollBox.css("height",iScrollBoxHeight); jqScrollBar.css("height",iScrollBarHeight); //计算拖拽边界。加入拖拽事件 var oBoundary = {iMinTop:opts.iTop}; oBoundary.iMaxTop = iScrollBoxHeight - Math.round(iRate*iScrollBoxHeight)+opts.iTop; oBoundary.iMinLeft = jqThis.innerWidth() - opts.iWidth - opts.iRight; oBoundary.iMaxLeft = oBoundary.iMinLeft; fnScrollContent(jqThis,jqChild,jqScrollBox,jqScrollBar,0,opts.iTop); jqScrollBar.draggable({oBoundary:oBoundary}); } }, __destroyer:function(ele){ var jqEle = $(ele); if(jqEle.data($.zUI.panel.sFlagName)){ var opts = jqEle.data($.zUI.panel.sOptsName); jqEle.children("."+opts.sBoxClassName).remove(); jqEle.children("."+opts.sBarClassName).remove(); } }});

有几点须要说明:

1.jQuery没有对鼠标滑轮滚动事件做兼容,所以,这里要使用原生的事件:

ff中叫做DOMMouseScroll:通过事件的detail属性得知鼠标的滚动情况,向下滚动为正,向上为负。以3的倍数标书滚动距离

其它叫做mousewheel,通过事件的wheelDelta能够得知鼠标的滚动情况。向上滚动为正,向下为负,以120的倍数标书滚动距离

以上代码使用jQuery的on来挂载事件,须要还要注意获取原生的event对象-->ev.originalEvent;

吐个槽:这里怎么是ff和其它浏览器。而不是IE和其它浏览器了呢~~~~

2.在事件mouseenter中,每次都会调用fnFreshScroll。就是说,每次鼠标移过来的时候,都会动态计算一遍滚动栏的大小,事实上就是为了兼容内容会动态变化的情况(也不是全部情况都能够,当内容变得非常少时,小于外层的高度。还是会有问题)

3.以上代码把全部的事件都放在了oEvent对象中。却没有加入到相应元素中,这是由于我对插件先封装了一层(你可能已经猜到。没错,就是开头的$.zUI.addWidget函数)。加入事件会在那一层中做。

在写这个插件的过程中,我将一些规范直接转成代码,写了一个插件骨架:

$.zUI = $.zUI || {}$.zUI.emptyFn = function(){};$.zUI.asWidget = [];/* * core代码,定义添加一个插件的骨架 */$.zUI.addWidget = function(sName,oSefDef){	//设置规范中的常量sFlagName、sEventName、sOptsName	$.zUI.asWidget.push(sName);	var w = $.zUI[sName] = $.zUI[sName] || {};	var sPrefix = "zUI" + sName	w.sFlagName = sPrefix;	w.sEventName = sPrefix + "Event";	w.sOptsName = sPrefix + "Opts";	w.__creator = $.zUI.emptyFn;	w.__destroyer = $.zUI.emptyFn;	$.extend(w,oSefDef);	w.fn = function(ele,opts){		var jqEle = $(ele);		jqEle.data(w.sOptsName,$.extend({},w.defaults,opts));		//假设该元素已经运行过了该插件,直接返回,仅相当于改动了配置參数		if(jqEle.data(w.sFlagName)){			return;		}		jqEle.data(w.sFlagName,true);		w.__creator(ele);		jqEle.on(jqEle.data(w.sEventName));	};	w.unfn = function(ele){		w.__destroyer(ele);		var jqEle = $(ele);//移除监听事件		if(jqEle.data(w.sFlagName)){			jqEle.off(jqEle.data(w.sEventName));			jqEle.data(w.sFlagName,false);		}	}	}

在写draggable插件时。我定义了几个规范,比方主体函数必须叫做fn,销毁函数必须叫做unfn,这里能够看到,在addWidget组件中定义了fn函数,并写下了骨架。__creator和__destroyer则须要详细插件实现,同样的代码,同样的逻辑放在骨架中,比方。以某种规则给插件须要用到的常量起名字。插件參数初始化的逻辑。插件第二次运行相当于改动參数而已,不会反复运行的逻辑~~~~

最后。把$上的统一方法放到$.fn上~~。这个在上一节中说过,$.zUI.asWidget是一个数组。里面放着插件的名字。这些名字自然是在$.zUI.addWidget这个函数中放进去的~~~

$.each($.zUI.asWidget,function(i,widget){	unWidget = "un"+widget;	var w = {};	w[widget] = function(args){			this.each(function(){			$.zUI[widget].fn(this,args);		});		return this;	};	w[unWidget] = function(){			this.each(function(){			$.zUI[widget].unfn(this);		});		return this;	}	$.fn.extend(w);});

实现的效果

结语:

不得不说。这不算一个panel。由于没有横向滚动栏,有两个原因,一是由于比較懒。不想实现了,原理类似,另外我比較讨厌横向滚动栏~~~

想下载源码的请看这里:

本文转自mfrbuaa博客园博客,原文链接:http://www.cnblogs.com/mfrbuaa/p/5362200.html,如需转载请自行联系原作者

你可能感兴趣的文章