1. 程式人生 > >子元素scroll父元素容器不跟隨滾動JS實現

子元素scroll父元素容器不跟隨滾動JS實現

方法 事件 tip 滾動頁面 學習 ima 使用方法 阻止 補充

小tip: 子元素scroll父元素容器不跟隨滾動JS實現

一、開場暖身

網上常見蹲來蹲去的小段子,比方說:“李代沫蹲,李代沫蹲,李代沫蹲完黃海波蹲;黃海波蹲,黃海波蹲,黃海波蹲完寧財神蹲;寧財神蹲,寧財神蹲,寧財神蹲完張耀揚蹲;張耀揚蹲,張耀揚蹲,張耀揚蹲完郭美美蹲;郭美美蹲,郭美美蹲,郭美美蹲完……”。應該源自“蘿蔔蹲,蘿蔔蹲,蘿蔔蹲完蘋果蹲……”。

在網頁中,滾動條的滾動行為也是類似的調調,如果頁面出現多個內嵌滾動條,則行為表現是:子元素滾,子元素滾,子元素滾完父元素滾;父元素滾,父元素滾,父元素滾完容器滾……

比方說下面:

技術分享圖片

在妹子臉上滾,先是妹子滾,妹子滾完主頁面滾,對吧~

//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實現