自己寫一個jQuery垂直捲軸外掛程式(panel)

來源:互聯網
上載者:User

標籤:外掛程式   panel   jquery   自訂   原始碼   

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 = $("<div style='position:absolute;display:none;line-height:0;'></div>");jqScrollBox.addClass(opts.sBoxClassName);//建立捲軸var jqScrollBar= $("<div style='position:absolute;display:none;line-height:0;'></div>");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;//擷取原生的eventif(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" + sNamew.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,因為沒有橫向捲軸,有兩個原因,一是因為比較懶,不想實現了,原理類似,另外我比較討厭橫向捲軸~~~

想下載原始碼的請看這裡:原始碼

自己寫一個jQuery垂直捲軸外掛程式(panel)

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.