原生JS实现自定义滚动条

浏览器带给我们的滚动条

.test{
            width: 300px;
            height: 100px;
            overflow: auto;
        }

原生JS实现自定义滚动条_第1张图片
于是我们可能与我们的界面不搭,或则不好看,不符合…那么可以自己自定义一个。或则,希望自己有一双发现美的卡姿兰大眼睛…

大概思路方向

这里的思路不是指马克思主义道路,指我们可以大概思考一下代码怎样的实现…

  1. 我们可以先根据内容求出滚动条的高度
  2. 当鼠标进入时容器,鼠标按住,则滚动条跟鼠标在容器的盒子走动
  3. 滚动条滚动,根据定位,内容盒子跟着滚动
  4. 鼠标离开则不滚动

HTML结构

一个大容器放左边一个容器,右边一个,左边容器放超出的内容(测试文本尽可能多点);右边容器放滚动条

    <div class="box">
        <div class="left_con">
            <div class="box_text">
                    Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris facilisis enim libero, at lacinia diam fermentum id. Pellentesque habitant morbi tristique senectus et netus.
                    Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris facilisis enim libero, at lacinia diam fermentum id. Pellentesque habitant morbi tristique senectus et netus.
                    Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris facilisis enim libero, at lacinia diam fermentum id. Pellentesque habitant morbi tristique senectus et netus.
                    Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris facilisis enim libero, at lacinia diam fermentum id. Pellentesque habitant morbi tristique senectus et netus.
                    Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris facilisis enim libero, at lacinia diam fermentum id. Pellentesque habitant morbi tristique senectus et netus.Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris facilisis enim libero, at lacinia diam fermentum id. Pellentesque habitant morbi tristique senectus et netus.Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris facilisis enim libero, at lacinia diam fermentum id. Pellentesque habitant morbi tristique senectus et netus.结尾处
            div>
        div>
        <div class="right_con">
            <div class="box_scroll">div>
        div>
    div>

CSS结构

如果没有定位需要在盒子中设置


先了解一下API

  • scroll家族
    scrollHeight: 一个元素的 scrollTop 值是这个元素的顶部到视口可见内容(的顶部)的距离的度量。(即元素被卷去的部分),而文档(body)则需要兼容,值被浏览器卷去的距离
    Element.scrollHeight 这个只读属性是一个元素内容高度的度量,包括由于溢出导致的视图中不可见内容。
  • client家族
    e.clienY 通常是鼠标距离我们浏览器最上面的距离(不是页面)
    clientHeight 可以通过 CSS height + CSS padding - 水平滚动条高度 (如果存在)来计算.
    clientTop 一个元素顶部边框的宽度(以像素表示)。不包括顶部外边距或内边距。clientTop 是只读的。
  • page
    pageX 是一个由MouseEvent接口返回的相对于整个文档的y(垂直)坐标以像素为单位的只读属性。
  • offset家族
    offsetHeight 元素的高度(包括边框和padding)
    offsetTop 获取距离其定位父盒子以上层级的位置,没有则以body
  • window.getSelection()
    返回一个 Selection 对象,表示用户选择的文本范围或光标的当前位置。
  • 鼠标滚轮事件
    onmousewheel

JS分步骤实现滚动

  1. 获取
let boxText = document.querySelector('.box_text')
let leftCon = document.querySelector('.left_con')
let rightCon = document.querySelector('.right_con')
let boxScroll = document.querySelector('.box_scroll')
let textH = boxText.scrollHeight 
let leftH = leftCon.offsetHeight 
let rightH = rightCon.offsetHeight
  1. 先将滚动条的高度算出来(高度比例 leftCon/boxText = boxScroll/rightCon)
boxScroll.style.height = parseInt(leftH/textH*rightH) + 'px'

1.也可以自己在css设置一个高度,最后通过左边的滚动距离来算出,当滚动条滚动的距离,根据比例算出滚动内容应该滚动的距离
3. 当鼠标在滚动条按下的时候,获取一些主要的信息

    let bool = false //设置开启滚动条是否可以滚动
    let startY //记录每一次鼠标开启的初始位置
       boxScroll.onmousedown = function(e){
        // 3.1 对e做以下兼容
        e = window.event || e
        bool = true //开启滚动
        startY = e.pageY //记录鼠标按下的初始位置
    }
  1. 滚动条随鼠标移动
   // 按住滚动条boxScroll时,滚动条随着移动
    document.onmousemove = function(e){
        //滚动条随着移动
        if(!bool){
            return 
        }
        boxScroll.style.top = e.pageY - startY + 'px'
    }
  1. 此时需要限制滚动条的范围
    我们可以知道滚动条最小为0,最大为高度项间rightCon-boxScroll
let barY //滚动条的滚动距离
......
barY = e.pageY - startY
        if(barY<0){
            barY = 0
        }else if(barY>rightH-boxScroll.clientHeight){
            barY = rightH-boxScroll.clientHeight
        }
        boxScroll.style.top =  barY + 'px'
  1. 文字随着鼠标的滚动而滚动
    因为我们滚动条的高度是已经通过比例算出来的,所以我们不用使用(内容移动的最大距离/内容移动的距离=滚动条移动的最大距离/滚动条的距离),我们直接使用rightH/boxScroll.clientHeight*滚动条的距离即可
boxScroll.style.top =  barY + 'px'
boxText.style.top = -barY *(rightH/boxScroll.clientHeight) + 'px'
  1. 鼠标弹起时记录滚动的位置,防止下次滚动回到0
let endY = 0 //初始化为0
document.onmouseup = function(e){
    bool = false //滚动完毕
    endY = boxScroll.offsetTop //此时记录滚动条的位置,为下次滚动不回使得滚动条回到0
}
  1. 禁止选中文本
    我们发现每次我们在使用滚动条时,都会选中内容
window.getSelection ? window.getSelection().removeAllRanges() : document.selection.empty()

这是兼容写法,其实是选中后又取消

整合

<script>
    let boxText = document.querySelector('.box_text')
    let leftCon = document.querySelector('.left_con')
    let rightCon = document.querySelector('.right_con')
    let boxScroll = document.querySelector('.box_scroll')
    let textH = boxText.scrollHeight //768
    let leftH = leftCon.offsetHeight //500
    let rightH = rightCon.offsetHeight
    boxScroll.style.height = parseInt(leftH/textH*rightH) + 'px'
    let bool = false 
    let startY 
    let barY 
    let endY = 0 
    // let scrollT
    boxScroll.onmousedown = function(e){
        e = window.event || e
        bool = true 
        startY = e.pageY 
    }
    document.onmousemove = function(e){
     	e = window.event || e
        if(!bool){
            return 
        }
        barY = e.pageY - startY + endY
        if(barY<0){
            barY = 0
        }else if(barY>rightH-boxScroll.clientHeight){
            barY = rightH-boxScroll.clientHeight
        }
        boxScroll.style.top =  barY + 'px'
        boxText.style.top = -barY *(rightH/boxScroll.clientHeight) + 'px'
        window.getSelection ? window.getSelection().removeAllRanges() : document.selection.empty()
    }
    document.onmouseup = function(e){
        bool = false 
        endY = boxScroll.offsetTop
    }
</script>

完善

可以给内容添加滚轮事件,然后内容滚动,滚动条跟着滚动;可能有更简单的思路;不同结构实现的方式可能不一致
isScroll
[better-scroll](https://ustbhuangyi.github.io/better-scroll/doc/zh-hans/#better-scroll 是什么)

你可能感兴趣的:(js)