溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

怎么使用div實(shí)現(xiàn)自制滾動(dòng)條

發(fā)布時(shí)間:2021-05-24 10:44:54 來(lái)源:億速云 閱讀:220 作者:小新 欄目:web開(kāi)發(fā)

這篇文章將為大家詳細(xì)講解有關(guān)怎么使用div實(shí)現(xiàn)自制滾動(dòng)條,小編覺(jué)得挺實(shí)用的,因此分享給大家做個(gè)參考,希望大家閱讀完這篇文章后可以有所收獲。

滾動(dòng)條是瀏覽器中最常見(jiàn)的組件了。然而,滾動(dòng)條的顏值總是不能令人滿意,特別是嵌入在頁(yè)面中的滾動(dòng)條:

怎么使用div實(shí)現(xiàn)自制滾動(dòng)條

漂亮的網(wǎng)頁(yè)突然出現(xiàn)一根灰灰的滾動(dòng)條真是太煞風(fēng)景了。雖然瀏覽器也提供了一些偽類能改善滾動(dòng)條的外觀,但改善程度也是有限。為什么不自己用 div 實(shí)現(xiàn)一根萌萌的滾動(dòng)條呢,比如這根:

怎么使用div實(shí)現(xiàn)自制滾動(dòng)條

貪吃蛇滾動(dòng)條

今天就來(lái)講講如何用 div 自己實(shí)現(xiàn)滾動(dòng)條。

1. 先得有滾動(dòng)條

在開(kāi)始之前,我們要先隱藏瀏覽器本身的滾動(dòng)條,加上自制的滾動(dòng)條

<body>
  <div id="container">
    <div class="scrollbar"></div>
    bla bla bla ... 一大段一屏顯示不下的內(nèi)容
  </div>
</body>

我們?cè)谛枰獫L動(dòng)條的 div 中增加了一個(gè) class="scroll" 的 div 代表滾動(dòng)條,給這個(gè) div 來(lái)點(diǎn)樣式:

html, body, #container {
    height: 100%;
    margin: 0;
}
#container {
    padding: 2rem;
    box-sizing: border-box; // 為了設(shè)置padding時(shí)不增加元素本身高度,避免出現(xiàn)滾動(dòng)條
    overflow-y: hidden; // 隱藏瀏覽器本身的滾動(dòng)條
    position: relative;
    padding-right: 30px; // 給自制滾動(dòng)條留點(diǎn)空間,不要其他內(nèi)容重合了
}
.scrollbar {
    height: 166px;
    width: 20px;
    border-radius: 20px;
    background: #ccc;
    position: absolute; // 絕對(duì)定位,方便設(shè)置滾動(dòng)條位置
    right: 0; // 設(shè)置滾動(dòng)條在最右邊
}

一個(gè)簡(jiǎn)易的滾動(dòng)條就有了:

怎么使用div實(shí)現(xiàn)自制滾動(dòng)條

雖然比瀏覽器默認(rèn)的滾動(dòng)條好不到哪兒去,不過(guò)你可以自由發(fā)揮,把GIF動(dòng)圖作為滾動(dòng)條也是可以的。由于滾動(dòng)條是 absolute 定位的,后面就通過(guò) top 屬性來(lái)控制滾動(dòng)條的位置。

現(xiàn)在滾動(dòng)條還是靜態(tài)的,想要讓他動(dòng)起來(lái),就要先了解下滾動(dòng)條與文檔滾動(dòng)的關(guān)系。

2. 滾動(dòng)條與文檔滾動(dòng)的關(guān)系

先看這張圖

怎么使用div實(shí)現(xiàn)自制滾動(dòng)條

藍(lán)色框代表一個(gè)很長(zhǎng)的文檔,文檔的高度可以通過(guò) scrollHeight 屬性獲得。

屏幕一下子顯示不了那么多內(nèi)容,只能顯示紅色區(qū)域部分,紅色區(qū)域就稱為”視口“(Viewport),視口的高度可以通過(guò) offsetHeight 屬性獲得。

頁(yè)面剛加載時(shí),視口的頂部和文檔頂部是重合的,滾動(dòng)條(綠色豎條)也在最頂部。當(dāng)我們將滾動(dòng)條下拉時(shí),文檔的內(nèi)容在向上滾動(dòng),其實(shí)是視口在向下移動(dòng):

怎么使用div實(shí)現(xiàn)自制滾動(dòng)條

視口向下移動(dòng)后,與文檔頂部就有了個(gè)偏移,這個(gè)偏移可以通過(guò) scrollTop 獲得。視口下移的同時(shí),滾動(dòng)條與頂部也有一段距離了,暫且用 h 表示。

視口里文檔頂部的最大距離可以是多少?根據(jù)圖可以看出是 scrollHeight - offsetHeight;類似地,滾動(dòng)條最大可以滾動(dòng)的距離是 offsetHeight - barHeight,其中 barHeight 是滾動(dòng)條本身的高度。

看到這里你是否有些明白了,滾動(dòng)條滾動(dòng)的距離,與文檔視口離開(kāi)頂部的距離是成一定比例的。滾動(dòng)條滑動(dòng)多少距離,文檔視口就按比例滑動(dòng)多少距離。而這個(gè)比例值就等于:

ratio = (scrollHeight - offsetHeight) / (offsetHeight - barHeight)

假設(shè)文檔總長(zhǎng) 5000px,視口高度1080px,滾動(dòng)條滑塊高 40px,那么根據(jù)公式計(jì)算出比例值是 3.77。也就是說(shuō),滾動(dòng)條每滾動(dòng) 1px,視口就要下移 3.77px

利用這個(gè)比例值,我們就可以讓滾動(dòng)條和視口等比例地進(jìn)行滑動(dòng)了。

3. 通過(guò)JavaScript控制滾動(dòng)條

在自制的滾動(dòng)條中,滾動(dòng)通過(guò)兩種事件觸發(fā),我們需要自己處理事件:

  1. 鼠標(biāo)滾輪滾動(dòng)時(shí),更新視口位置,同時(shí)按比例更新滾動(dòng)條的位置

  2. 鼠標(biāo)拖拽滾動(dòng)條時(shí),更新滾動(dòng)條位置,同時(shí)按比例更新視口位置

3.1 鼠標(biāo)滾輪事件

鼠標(biāo)滾輪滾動(dòng)時(shí),會(huì)觸發(fā) mousewheel 事件,此時(shí)需要根據(jù)滾動(dòng)增量(e.deltaY)更新視口位置,在根據(jù)新的視口位置推算出滾動(dòng)條的位置。代碼:

container.addEventListener('mousewheel', function(e) {
    this.scrollTop += e.deltaY;
    this.scrollbar.style.top = (this.scrollTop + this.scrollTop / this.ratio) + 'px';
});

可以看到,滾動(dòng)條的 top 值就是當(dāng)前視口的偏移(scrollTop)加上這個(gè)偏移的按比例縮小。

3.2 鼠標(biāo)拖拽事件

JavaScript 原生沒(méi)有拖拽事件,需要用左鍵點(diǎn)下(mousedown),鼠標(biāo)移動(dòng)(mousemove),左鍵放開(kāi)(mouseup)三個(gè)事件配合模擬出拖拽效果:

container.addEventListener('mousedown', function (e) {
    if (e.target === this.scrollbar) {
        this.prevY = e.pageY;
    }
});
container.addEventListener('mouseup', function (e) {
    this.prevY = null;
});
container.addEventListener('mousemove', function (e) {
    if (this.prevY) {
        // 此時(shí)可以確定用戶在表示拖拽
    }
    e.preventDefault();
});

上面的代碼在處理 mousemove 事件時(shí)使用 e.preventDefault() 阻止瀏覽器默認(rèn)動(dòng)作,您可以自行嘗試加上和不加這行的效果。接著上面的代碼,我們處理拖拽動(dòng)作:

if (this.prevY) {
    // 此時(shí)可以確定用戶在表示拖拽
    this.scrollTop += (e.pageY - this.prevY) * this.ratio;
    this.scrollbar.style.top = (this.scrollTop + this.scrollTop / this.ratio) + 'px';
    this.prevY = e.pageY;
}

與滾輪滾動(dòng)不同,JavaScript沒(méi)有給出每次拖拽的移動(dòng)增量,需要自己計(jì)算,并每次存儲(chǔ)上一次的鼠標(biāo)位置。

至此一個(gè)可用的自制滾動(dòng)條就完成了。

完整代碼

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <style>
        html, body, #container {
            height: 100%;
            margin: 0;
        }
        #container {
            padding: 2rem;
            box-sizing: border-box;
            overflow-y: hidden;
            position: relative;
            padding-right: 30px;
        }
        .scrollbar {
            height: 166px;
            width: 20px;
            border-radius: 20px;
            background: #ccc;
            position: absolute;
            right: 0;
        }
    </style>
    <script>
    window.onload = function () {
        var scrollbar = document.querySelector('.scrollbar');
        var container = scrollbar.parentNode;
        container.scrollbar = scrollbar;
        container.ratio =
            (container.scrollHeight - container.offsetHeight) / (container.offsetHeight - scrollbar.offsetHeight);
        container.addEventListener('mousewheel', function(e) {
            this.scrollTop += e.deltaY;
            this.scrollbar.style.top = (this.scrollTop + this.scrollTop / this.ratio) + 'px';
        });
        container.addEventListener('mousedown', function (e) {
            if (e.target === this.scrollbar) {
                this.prevY = e.pageY;
            }
        });
        container.addEventListener('mouseup', function (e) {
            this.prevY = null;
        });
        container.addEventListener('mousemove', function (e) {
            if (this.prevY) {
                this.scrollTop += (e.pageY - this.prevY) * this.ratio;
                this.scrollbar.style.top = (this.scrollTop + this.scrollTop / this.ratio) + 'px';
                this.prevY = e.pageY;
            }
            e.preventDefault();
        });
    }
    </script>
</head>
<body>
    <div id="container">
        <div class="scrollbar"></div>
        bla, bla, bla... 一大段很長(zhǎng)的文字
    </div>
</body>
</html>

關(guān)于“怎么使用div實(shí)現(xiàn)自制滾動(dòng)條”這篇文章就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,使各位可以學(xué)到更多知識(shí),如果覺(jué)得文章不錯(cuò),請(qǐng)把它分享出去讓更多的人看到。

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

div
AI