子元素scroll父元素容器不跟隨滾動JS實現
小tip: 子元素scroll父元素容器不跟隨滾動JS實現
本文地址(轉載):http://www.zhangxinxu.com/wordpress/?p=5092
一、開場暖身
網上常見蹲來蹲去的小段子,比方說:“李代沫蹲,李代沫蹲,李代沫蹲完黃海波蹲;黃海波蹲,黃海波蹲,黃海波蹲完寧財神蹲;寧財神蹲,寧財神蹲,寧財神蹲完張耀揚蹲;張耀揚蹲,張耀揚蹲,張耀揚蹲完郭美美蹲;郭美美蹲,郭美美蹲,郭美美蹲完……”。應該源自“蘿蔔蹲,蘿蔔蹲,蘿蔔蹲完蘋果蹲……”。
在網頁中,滾動條的滾動行為也是類似的調調,如果頁面出現多個內嵌滾動條,則行為表現是:子元素滾,子元素滾,子元素滾完父元素滾;父元素滾,父元素滾,父元素滾完容器滾……
比方說下面:
在妹子臉上滾,先是妹子滾,妹子滾完主頁面滾,對吧~
//zxx: 別問為什麽不使用張含韻,因為張妹子照片是橫的,滾動空間小,曉得伐~
這是瀏覽器的默認行為,如果我們遇到了一個需求:子元素滾,子元素滾完,就完了,父元素不需要滾了。那該如何實現呢?
在PC端,OK,本文介紹的方法,值適用於PC端,移動端,咳咳,我15年就沒做過移動端項目,不好意思,手生,我也沒去研究。
補充於翌日
移動端的處理,可以參見@hacke2的這篇文章:“在移動端上使用原生滑屏解決方案”
二、阻止瀏覽器默認行為的特定套路
哈,本文標題有些拗口,實際上用一句話概括就是:如何阻止瀏覽器的默認滾動行為。
基本上,好像印象中就沒有例外的,阻止瀏覽器的默認行為,就一條(假設事件對象參數是event):event.preventDefault()
.
這是標準規範使用方法。但是,對於老IE瀏覽器,event.returnValue = false
. 如果你使用jQuery等框架,直接上面的event.preventDefault()
就可以,庫已經幫你搞定了兼容細節處理。
OK,回到本文。阻止默認滾動,也是類似,關鍵是找到準確的事件。
第一反應是scroll
事件,不知道是不是我測試的方法不對,結果沒鳥用;其實想想也可以理解,scroll事件要觸發,尼瑪必須已經滾動了哈~
後來,發現要從滾動事件的源頭處理起來。在PC端,絕大多數滾動都是鼠標滾動觸發的(上下快捷鍵也可以滾動頁面,但一般人不知道),因此,我們可以從鼠標滾輪事件入手。
三、鼠標滾輪事件
JS基礎知識的啦,mousewheel
事件:
dom.onmousewheel = function() { // 嘿嘿嘿 };
IE, Chrome都認識,但是FireFox瀏覽器,要使用DOMMouseScroll, 具體知識呢我之前有寫過文章分析過:“JS滾輪事件(mousewheel/DOMMouseScroll)了解”。現在回過頭看看這篇文章,內容和點都挺好。但是,當時正好在學習模塊化開發,以及JavaScript語言模式,所以,提供的代碼,科科,不是拿來主義的調調,所以這篇文章沒有火啊~
扯遠了,總之呢,我們對鼠標滾動這個事件,進行event.preventDefault()
,頁面就像齒輪卡殼了一樣,滾不動了!
四、原理爬上來
找到了關鍵鑰匙,現在就要開門了。
子元素可以滾,父元素不能滾。
我們可以對子元素寫上鼠標滾輪事件,對吧,的那個子元素滾動到邊界的時候,我們立馬插一刀event.preventDefault()
。幹掉整個頁面的滾動,世界一下子安靜了,時間好像突然靜止了一般,好像很不錯的樣子哦!
於是,寡人我屁顛屁顛搞起代碼(粗糙示意):
if (direction == ‘up‘ && scrollTop == 0) { event.preventDefault() }
翻譯下就是:哥哥我往上滾,當滾到頭的時候,頁面滾動歇菜。
Chrome一測試,喔噢,好棒,鼓掌! FireFox一測試,喔噢,好棒too,鼓掌again! IE一測試,喔噢,好…………尼瑪,滾蛋了~ 滾動高度直接跳過了0,直接把父元素給滾了。
靠,什麽鬼?不兼容,搞不定,怎麽辦?
五、臨界手動翻滾
就是說,我們不要到0或者最大滾動高度時候,再去阻止默認滾動,我們要在到達邊界的前一個滾動,就開始下手,手動滾動到邊界,同時event.preventDefault()
阻止鼠標滾動行為。於是,IE瀏覽器也棒棒噠了!
說實話,從開頭到現在,中文啪啪啪敲了這麽多,其實毛線用都沒有,從度娘或谷哥過來的同學需要的不是什麽神神叨叨的廢話,需要的只是下面這段可以直接拿來主義的代碼,好吧,拿去吧——子元素滾完就滾完的方法源代碼:
$.fn.scrollUnique = function() { return $(this).each(function() { var eventType = ‘mousewheel‘; // 火狐是DOMMouseScroll事件 if (document.mozHidden !== undefined) { eventType = ‘DOMMouseScroll‘; } $(this).on(eventType, function(event) { // 一些數據 var scrollTop = this.scrollTop, scrollHeight = this.scrollHeight, height = this.clientHeight; var delta = (event.originalEvent.wheelDelta) ? event.originalEvent.wheelDelta : -(event.originalEvent.detail || 0); if ((delta > 0 && scrollTop <= delta) || (delta < 0 && scrollHeight - height - scrollTop <= -1 * delta)) { // IE瀏覽器下滾動會跨越邊界直接影響父級滾動,因此,臨界時候手動邊界滾動定位 this.scrollTop = delta > 0? 0: scrollHeight; // 向上滾 || 向下滾 event.preventDefault(); } }); }); };
沒錯,依賴jQuery的一個擴展方法,上面代碼只要拷貝到你頁面的JS中,然後,你希望哪個元素滾動到底,父級不滾動,直接:
$().scrollUnique();
就可以了,然後就可以打卡下班了。
對了,有個demo, 您可以狠狠地點擊這裏:裏面元素滾動到底外部容器不滾動demo
如果您的顯示器豎屏,或者寬度1920的,會發現右側沒有大滾動條,則,麻煩大家手動高度改小,拉拉窗口啊,或者打開控制臺之類的。
//zxx: 你問我什麽不加高頁面造一個滾動條?唉,舍不得把底部的廣告刻意藏在滾動條之外~
六、拋磚引玉
前文也提到,頁面滾動條滾動的事件源很多,不僅僅是鼠標滾動,上下鍵,End鍵, Home鍵等都有滾動定位行為。因此,大家要想100%全方位封殺滾動行為,僅僅上面的鼠標滾動代碼是不夠的,但是,關鍵鑰匙已經給大家了,大家可以依次,按照自己的項目需求進行進一步深入拓展。
不過,我個人覺得,上面mousewheel
處理已經足夠了,什麽鍵盤觸發滾動,讓他自己去玩耍吧,還是別折騰了,吃力不討好。
喲,寫完了,擡頭一看,一張截圖都沒有,這可不行,風水不能斷,搞一張。
恩,不錯,真正的無可挑剔的「截」圖。
子元素scroll父元素容器不跟隨滾動JS實現