原生js实现自定义滚动条组件

下面我来详细讲解如何原生js实现自定义滚动条组件。

1. 确定组件需求

在实现自定义滚动条组件前,我们需要先确定组件的需求。一般来说,自定义滚动条组件需要具备以下功能:

  • 拖动滑块来实现滚动;
  • 点击轨道实现精准跳转;
  • 自适应内容高度,并根据显示内容的变化而动态更新滚动条长度;
  • 能够跨浏览器平台使用。

2. 组件结构设计

组件的结构设计需要包含以下元素:

  • 一条轨道,包含一个可拖动的滑块;
  • 显示内容区域。

因此,我们可以参考以下代码:

<div class="scroll-wrapper">
    <div class="scroll-content">
        // 显示内容区域
    </div>
    <div class="scroll-track">
        <div class="scroll-bar"></div>
        // 滑块
    </div>
</div>

3. 编写组件的CSS样式

接下来,我们需要编写组件的CSS样式。需要注意的是,我们需要判断浏览器是否需要添加滚动条。如果需要,则隐藏浏览器默认滚动条,并添加自定义滚动条组件。

以下是CSS样式的示例代码:

/* 隐藏默认滚动条 */
body::-webkit-scrollbar {
    display: none;
}
/* 组件样式 */
.scroll-wrapper {
    position: relative;
    overflow: hidden;
    /* 容器尺寸 */
    height: 300px;
    width: 400px;
}
.scroll-content {
    position: absolute;
    /* 内容尺寸 */
    height: 100%;
    width: 100%;
    /* 添加padding,避免出现遮挡 */
    padding-right: 15px;
}
.scroll-track {
    position: absolute;
    /* 轨道尺寸 */
    right: 0;
    top: 0;
    bottom: 0;
    width: 10px;
    /* 背景色 */
    background: #f1f1f1;
}
.scroll-bar {
    position: absolute;
    /* 滑块尺寸 */
    top: 0;
    left: 0;
    width: 100%;
    height: 50px;
    /* 滑块样式 */
    background-color: #333;
    border-radius: 5px;
    cursor: pointer;
}

4. 实现滚动条组件功能

4.1 功能1:拖动滑块实现滚动

实现步骤:

  1. 获取scroll-bar元素;
  2. scroll-bar元素添加鼠标按下、鼠标移动、鼠标松开事件;
  3. 鼠标按下时,记录滑块相对于轨道顶部的距离,记录滑块上一次的位置;
  4. 鼠标移动时,计算滑块当前位置,并将其移动到该位置上;
  5. 鼠标松开时,将事件绑定移除。

以下是实现代码:

let scrollBar = document.querySelector('.scroll-bar');

scrollBar.addEventListener('mousedown', (e) => {
    // 记录相对于轨道顶部的距离
    let offsetY = e.clientY - scrollBar.offsetTop;
    // 记录滑块上一次的位置
    let lastY = scrollBar.offsetTop;

    document.addEventListener('mousemove', onMouseMove);
    document.addEventListener('mouseup', onMouseUp);

    function onMouseMove(e) {
        // 计算滑块当前位置
        let y = e.clientY - offsetY;
        // 滑块不能超出轨道
        if (y < 0) {
            y = 0;
        }
        let trackHeight = document.querySelector('.scroll-track').offsetHeight;
        if (y > trackHeight - scrollBar.offsetHeight) {
            y = trackHeight - scrollBar.offsetHeight;
        }

        // 将滑块移动到当前位置
        scrollBar.style.top = y + 'px';

        // 根据滑块位置计算出内容区应该滚动的距离
        let contentHeight = document.querySelector('.scroll-content').offsetHeight;
        let scrollDistance = y / (trackHeight - scrollBar.offsetHeight) * (contentHeight - trackHeight);

        // 将内容区移动到当前位置
        document.querySelector('.scroll-content').scrollTop = scrollDistance;
    }

    function onMouseUp() {
        // 移除事件绑定
        document.removeEventListener('mousemove', onMouseMove);
        document.removeEventListener('mouseup', onMouseUp);
    }
});

4.2 功能2:点击轨道跳转

实现步骤:

  1. 获取scroll-track元素;
  2. scroll-track元素添加点击事件;
  3. 计算出滑块的新位置,并将滑块移动到该位置上。

以下是实现代码:

let scrollTrack = document.querySelector('.scroll-track');

scrollTrack.addEventListener('click', (e) => {
    // 计算出滑块的新位置
    let trackHeight = scrollTrack.offsetHeight;
    let barHeight = scrollBar.offsetHeight;
    let y = e.clientY - scrollTrack.getBoundingClientRect().top - barHeight / 2;
    if (y < 0) {
        y = 0;
    } else if (y > trackHeight - barHeight) {
        y = trackHeight - barHeight;
    }

    // 将滑块移动到新位置
    scrollBar.style.top = y + 'px';

    // 根据滑块位置计算出内容区应该滚动的距离
    let contentHeight = document.querySelector('.scroll-content').offsetHeight;
    let scrollDistance = y / (trackHeight - barHeight) * (contentHeight - trackHeight);

    // 将内容区移动到当前位置
    document.querySelector('.scroll-content').scrollTop = scrollDistance;
});

4.3 功能3:自适应内容高度并更新滚动条长度

实现步骤:

  1. 获取scroll-wrapper元素和scroll-content元素;
  2. scroll-content元素高度变化时,计算并更新滑块的长度。

以下是实现代码:

let scrollWrapper = document.querySelector('.scroll-wrapper');
let scrollContent = document.querySelector('.scroll-content');

let mutationObserver = new MutationObserver((mutations) => {
    // 计算滑块长度
    let trackHeight = scrollWrapper.offsetHeight;
    let barHeight = Math.pow(trackHeight, 2) / scrollContent.scrollHeight;
    if (barHeight < 50) {
        barHeight = 50;
    }

    // 更新滑块长度
    scrollBar.style.height = barHeight + 'px';
});

mutationObserver.observe(scrollContent, {
    childList: true,
    subtree: true,
    characterData: true,
    attributes: true
});

5. 示例说明

以下是两个使用示例:

示例1:自定义滚动条组件使用示例

<div class="scroll-wrapper">
    <div class="scroll-content">
        <p>苟利国家生死以,岂因祸福避趋之!</p>
        <p>千磨万击还坚劲,任尔东西南北风。</p>
        <p>雨打梨花深闭门,忘了青春,误了青春。</p>
        <p>靡不有初,鲜克有终。</p>
        <p>未曾谋面时,心中缪隐似若神仙。</p>
        <p>前事不忘,后事之师。</p>
        <p>性格决定命运。</p>
        <p>不在高山,不在深谷。</p>
        <p>天空没有翅膀的痕迹,但鸟儿已经飞过。</p>
    </div>
    <div class="scroll-track">
        <div class="scroll-bar"></div>
    </div>
</div>

<style>
body::-webkit-scrollbar {
    display: none;
}
.scroll-wrapper {
    position: relative;
    overflow: hidden;
    /* 容器尺寸 */
    height: 300px;
    width: 400px;
}
.scroll-content {
    position: absolute;
    /* 内容尺寸 */
    height: 100%;
    width: 100%;
    /* 添加padding,避免出现遮挡 */
    padding-right: 15px;
}
.scroll-track {
    position: absolute;
    /* 轨道尺寸 */
    right: 0;
    top: 0;
    bottom: 0;
    width: 10px;
    /* 背景色 */
    background: #f1f1f1;
}
.scroll-bar {
    position: absolute;
    /* 滑块尺寸 */
    top: 0;
    left: 0;
    width: 100%;
    height: 50px;
    /* 滑块样式 */
    background-color: #333;
    border-radius: 5px;
    cursor: pointer;
}
</style>

<script>
let scrollBar = document.querySelector('.scroll-bar');

scrollBar.addEventListener('mousedown', (e) => {
    // 记录相对于轨道顶部的距离
    let offsetY = e.clientY - scrollBar.offsetTop;
    // 记录滑块上一次的位置
    let lastY = scrollBar.offsetTop;

    document.addEventListener('mousemove', onMouseMove);
    document.addEventListener('mouseup', onMouseUp);

    function onMouseMove(e) {
        // 计算滑块当前位置
        let y = e.clientY - offsetY;
        // 滑块不能超出轨道
        if (y < 0) {
            y = 0;
        }
        let trackHeight = document.querySelector('.scroll-track').offsetHeight;
        if (y > trackHeight - scrollBar.offsetHeight) {
            y = trackHeight - scrollBar.offsetHeight;
        }

        // 将滑块移动到当前位置
        scrollBar.style.top = y + 'px';

        // 根据滑块位置计算出内容区应该滚动的距离
        let contentHeight = document.querySelector('.scroll-content').offsetHeight;
        let scrollDistance = y / (trackHeight - scrollBar.offsetHeight) * (contentHeight - trackHeight);

        // 将内容区移动到当前位置
        document.querySelector('.scroll-content').scrollTop = scrollDistance;
    }

    function onMouseUp() {
        // 移除事件绑定
        document.removeEventListener('mousemove', onMouseMove);
        document.removeEventListener('mouseup', onMouseUp);
    }
});

let scrollTrack = document.querySelector('.scroll-track');

scrollTrack.addEventListener('click', (e) => {
    // 计算出滑块的新位置
    let trackHeight = scrollTrack.offsetHeight;
    let barHeight = scrollBar.offsetHeight;
    let y = e.clientY - scrollTrack.getBoundingClientRect().top - barHeight / 2;
    if (y < 0) {
        y = 0;
    } else if (y > trackHeight - barHeight) {
        y = trackHeight - barHeight;
    }

    // 将滑块移动到新位置
    scrollBar.style.top = y + 'px';

    // 根据滑块位置计算出内容区应该滚动的距离
    let contentHeight = document.querySelector('.scroll-content').offsetHeight;
    let scrollDistance = y / (trackHeight - barHeight) * (contentHeight - trackHeight);

    // 将内容区移动到当前位置
    document.querySelector('.scroll-content').scrollTop = scrollDistance;
});

let scrollWrapper = document.querySelector('.scroll-wrapper');
let scrollContent = document.querySelector('.scroll-content');

let mutationObserver = new MutationObserver((mutations) => {
    // 计算滑块长度
    let trackHeight = scrollWrapper.offsetHeight;
    let barHeight = Math.pow(trackHeight, 2) / scrollContent.scrollHeight;
    if (barHeight < 50) {
        barHeight = 50;
    }

    // 更新滑块长度
    scrollBar.style.height = barHeight + 'px';
});

mutationObserver.observe(scrollContent, {
    childList: true,
    subtree: true,
    characterData: true,
    attributes: true
});
</script>

示例2:动态添加滚动动态内容

```html

滚动条中的动态内容。

  • Pjblog模板制作教程 超强推荐

    当您想要给自己的网站使用Pjblog模板时,可以按照以下攻略进行制作: 确定模板风格和结构 首先,需要确定模板的风格和结构。可以根据自己的需要,在已有的模板基础上进行修改,或者全新设计一个模板,确定好后就需要开始裁剪模板了。 对模板文件进行裁剪 根据模板结构,需要裁剪出若干个文件,然后分别放到对应的目录下。关于文件的格式和使用方法,可以参考Pjblog文档中…

    css 2023年6月9日
    00
  • IE7下父元素及子元素的隐藏顺序不当带来的display:none出现BUG

    在IE7浏览器中,当父元素使用display:none属性隐藏,子元素也使用display:none属性隐藏且先于父元素隐藏,再显示的时候会出现BUG,即子元素无法显示。要解决这个问题,可以执行以下步骤: 使用visibility:hidden代替display:none 在IE7浏览器下,使用visibility:hidden代替display:none能…

    css 2023年6月10日
    00
  • 合作推广
    合作推广
    分享本页
    返回顶部