原生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

滚动条中的动态内容。

  • DIV+CSS 网页布局心得

    下面是详细的“DIV+CSS 网页布局心得”的攻略。 一、制定网页布局方案 在进行网页布局前,需要先制定一个方案。该方案需要包括网页结构、页面元素的排列方式、样式设计等。可以先简单手绘或使用网页设计工具进行概念设计。 二、选择合适的HTML标签 正确的HTML标签是网页布局的基础,需要根据网页的语义以及页面元素之间的关系来选择合适的HTML标签。例如,文章内…

    css 2023年6月10日
    00
  • 通过 JS 判断页面是否有滚动条的实现方法

    判断页面是否有滚动条是 web 开发中常见的需求之一。可以通过 JS 判断页面是否有滚动条的实现方法有以下几种: 方法一:通过比较页面高度与窗口高度判断 在 HTML 的文档对象模型(DOM)中,document 对象的 scrollHeight 属性表示网页正文部分的高度。比较这个高度和窗口的高度,即可判断页面是否有滚动条。 if (document.bo…

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