随心所欲的滚动条,远离产品汪(一)

在我们的开发生活中,相信很多人都会遇到形形色色的项目需求,比如更改浏览器的默认样式,在产品定下需求后给的网页设计图中我们最常遇到的是自定义滚动条的样式,或者当你想构建一个很有特色和创意的网页,那么也肯定希望自己能够去设置滚动条样式,当然,做好准备才是最重要的,最近在项目中遇到了,正好来总结一下。

本文主要内容

1.基本原理图

2.结构布局分析

3.功能实现逻辑

4.实现步骤

5.小结

1.基本原理图

大家可以先根据原理图自己分析一波,有利于加深对下文的理解

2. 结构布局分析

我们在开发项目中会时不时的碰到这种情况,当滚动块B超出了父级可视部分,我们总会设置overflow的属性值来隐藏超出的部分,根据默认的滚动条来操作隐藏区的内容,当将可视区A设置overflow:auto时,网页会显示出默认的滚动条样式。

如图下所示,初始滚动条的效果:

此时我们会发现,有些时候设计师给出的设计图滚动条的样式是不同的或者默认的滚动条样式会影响到我们对网页的整体感觉,所以我们需要隐藏默认滚动条,将可视区设置为overflow:hidden,自己去重新设置滚动条的样式。

首先根据原理图,我们写出基本结构代码:

<body>
   <div class="wrap">
      <div class="con" id = "bx">//可视区A
         <p id="cn"> //滚动块B
            滚动块B内容
          </p>  
       </div>
       <div class="boxscr" id = "bs">//滚动条滚动区
          <div class="scr" id = "sc"></div> //滚动条
       </div>
    </div>
</body>

根据滚动条的上下滚动方式,我们可以想到可以通过控制margin-top和top的值来实现滚动条的滚动,本文中通过使用定位的方式来实现。

接下来我们完善具体的样式结构:

<!DOCTYPE html>
<html>
    <head>
        <title>自定义滚动条</title>
        <meta charset="utf-8">
        <style type="text/css">
.wrap {
            width: 200px;
            height: 150px;
            margin: 0 auto;
        }
        .con {
            float: left;
            overflow: auto;
            width: 180px;
            height: 150px;
            background: #39f;
        }
        .con p {
            margin: 0;
            color: #fff;
            text-align: center;
            line-height: 20px;
            font-size: 14px;
        }
        .boxscr {
            float: right;
            position: relative;
            width: 20px;
            height: 150px;
            background: #d9ecff;
        }
        .scr {
            position: absolute;
            width: 20px;
            border-radius: 10px;
            background: #c6ccff;
            cursor: pointer;
        }
    </style>
    </head>
    <body>
        <div class="wrap">
            <div class="con" id = "bx">
                <p id="cn">
                    HTML5学堂-自定义滚动条
                    HTML5学堂-自定义滚动条
                    HTML5学堂-自定义滚动条
                    HTML5学堂-自定义滚动条
                    HTML5学堂-自定义滚动条
                    HTML5学堂-自定义滚动条
                    HTML5学堂-自定义滚动条
                    HTML5学堂-自定义滚动条
                    HTML5学堂-自定义滚动条
                    HTML5学堂-自定义滚动条
                    HTML5学堂-自定义滚动条
                    HTML5学堂-自定义滚动条
                    HTML5学堂-自定义滚动条
                </p>  
            </div>
            <div class="boxscr" id = "bs">
                <div class="scr" id = "sc"></div>
            </div>
        </div>
    </body>
</html>

实现的效果:

ps:当前的效果样式只是个示例,大家可以根据自己的实际需求进行样式调整。

3. 功能实现逻辑

1. 通过控制滚动条的top值来实现滚动条的上下滚动,但是滚动块的内容有限,滚动条不可能无限滚动,所以滚动条有着自己的滚动范围。

2. 同理,滚动块B则通过可视区A的scrollTop来控制上下滚动,当然也有着自己的滚动范围。

3. 如何将两者关联起来呢,实际上细心的你已经发现:滚动条C的高度/滚动区D的高度 = 可视区A的高度/ 滚动块B的高度,即滚动块的滚动距离和滚动条的滚动距离它们的比都是存在联系的。

现在我们分几个步骤来实现它们。

4. 实现步骤

此处我们先上代码,然后根据代码来进行具体分析:

<script>
    var bx = document.getElementById("bx"),
        cn = document.getElementById("cn"),
        bs = document.getElementById("bs"),
        sc = document.getElementById("sc"),


        oldY = 0,      //鼠标初次点击的Y轴坐标
        newY = 0,      // 鼠标拖动时的Y轴坐标
        nowY = 0,      // 鼠标拖动时滚动条C距父级顶部的高度
        maxY = 0,      // 拖动的最大极限值
        nowDisY = 0,   // 点击滚动条C时距父级顶部的高度


        bxHeight = bx.clientHeight,  // 可视区A高度
        bsHeight = bs.clientHeight, //  滚动区D高度
        cnHeight = cn.offsetHeight;  // 滚动块B的高度


        // 根据滚动块B实际内容高度控制滚动条C的高度
        scHeight = bxHeight/cnHeight * bxHeight;
        sc.style.height = scHeight + "px";  


        // 当滚动块B实际高度小于可视区时,滚动条隐藏
        if (cnHeight < bxHeight) {
            bs.style.display = "none";
        };


        sc.onmousedown = function(e) {
            oldY = e.clientY;
            nowDisY = sc.offsetTop;         // 当前的滚动条C的top值
            e.preventDefault();
            document.onmousemove = function(e) {
                newY = e.clientY;
                nowY = nowDisY + newY - oldY;  // 拖动后的滚动条C的top值
                maxY = bsHeight - scHeight;    // 设置滚动条top极限值


                if (nowY <= 0) {
                    nowY = 0;
                };
                if (nowY >= maxY) {
                    nowY = maxY;
                };


            bx.scrollTop = nowY/maxY * (cnHeight - bxHeight);  // 设置滚动块B的scrollTop值
            sc.style.top = nowY + "px";
            }
        }
        document.onmouseup = function() {
            document.onmousemove = null;   
        }
</script>

a) 计算滚动条高度

因为滚动条C的高度不是一成不变的,需要滚动块B的实际高度与可视区A高的相似比来计算。

即:滚动块B的高/可视区A的高 = 滚动区D的高/滚动条C的高

scHeight = bxHeight/cnHeight * bxHeight;// 根据滚动块B实际内容高度控制滚动条C的高度
sc.style.height = scHeight + "px";  

b) 鼠标拖动时的坐标位置

无论开始鼠标点击滚动条哪一个位置,都将视为点击滚动条的顶点坐标。

即:滚动条的滚动距离 = 拖动后鼠标变化的Y值 – 点击时鼠标获取的Y值

nowY = nowDisY + newY - oldY;  // 拖动后的滚动条C的top值

c) 实现滚动条拖动

在实现滚动条拖动的同时,我们并不能忽视滚动条的当前位置,当二次拖动时,此时的滚动条或许已经偏离了初始位置。

即: 当前滚动条位置的top值 = 拖动后鼠标变化的Y值 – 点击时鼠标获取的Y值 + 初始滚动条的top值

nowY = nowDisY + newY - oldY;  // 拖动后的滚动条C的top值

d) 限制滚动条的拖动范围

滚动条有着自己的活动范围,即滚动条的top值有着自己的极限距离,当超过了极限距离,此时的top值就一直等于这个值,反之最小值也是如此,那么这个值是多少呢?

由原理图可知:0 <= 滚动条的top值 <= 滚动区D的高度 – 滚动条C的高度

maxY = bsHeight - scHeight;    // 设置滚动条top极限值
if (nowY <= 0) {
   nowY = 0;
};
if (nowY >= maxY) {
   nowY = maxY;
};

e) 所有东西都准备好了,怎么让滚动条C的滚动控制到滚动块B呢

首先我们需要知道,滚动块B可滚动的极限值,即可视区A的高 – 滚动块B的高。 滚动块B的滚动距离与滚动条C的滚动距离相呼应。

即: 可视区A的scrollTop = 顶点可移动极限值 * 滚动条滚动的比值

bx.scrollTop = nowY/maxY * (cnHeight - bxHeight);  // 设置滚动块B的scrollTop值
sc.style.top = nowY + "px";

这个时候,刷新下网页,就可以发现滚动条已经可以滚动了,同时也控制着内容区的滑动。

5.小结

自定义滚动条是基于拖拽的原理实现的,在学堂官网中,大家可以找到“拖拽”的相关知识去进一步巩固了解,回到当前,大家有没有发现还存在一些不好的地方呢?

1. 每次滚动都需要拖拽,很累啊,为什么鼠标滚轮不能用?

2. 并没有到考虑兼容问题。

由于篇幅原因,这里不再进行说明,将在下周同一时间更新自定义滚动条的续篇,着重为大家介绍滚轮事件的添加及兼容问题的解决。

本文系HTML5学堂独家内容,转载请在文章开头显眼处注明作者和出处“HTML5学堂(http://www.h5course.com/)”

原文发布于微信公众号 - HTML5学堂(h5course-com)

原文发表时间:2016-11-21

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏高爽的专栏

HTML锚点

        以前只是知道有锚点这么个东西,一直没有用到,昨天做毕设用到了锚点,现在总结一下控制锚点的几种情况:         1. 在同一页面中 <a n...

1700
来自专栏deepcc

弹出层高度不限垂直居中 兼容ie ff chrome

3379
来自专栏james大数据架构

AndroidManifest.xml配置文件 android.theme大全权限设置Android Permission中英对照

AndroidManifest.xml启动文件 主activity: <activity android:name="com.examp...

1655
来自专栏web开发

VUE滚动条插件——vue-happy-scroll

最近自己在自学vue2.0,然后就自己摸索做一个简单的后台管理系统,在做的过程中,总感觉不同浏览器自带的滚动条样式不统一,也很难看,所以就在网上找一些使用vue...

1934
来自专栏进击的君君的前端之路

jQuery实现图片懒加载

2412
来自专栏前端知识分享

第18天:京东网页头部制作

一、京东页面制作开始(头部) 1、浮动的盒子宽度由内容定,不需要设置宽度 2、绝对定位不占位置,相对定位占位置

662
来自专栏一个小程序员的成长笔记

CSS深入理解学习笔记之overflow

1、Overflow基本属性   overflow:visible(默认)/hidden/scroll/auto/inherit;   visible:超出部分...

2755
来自专栏偏前端工程师的驿站

JS魔法堂:关于元素位置和鼠标位置的属性

一、关于鼠标位置的属性                           1. 触发鼠标事件的区域       盒子模型中的border,padding,co...

17910
来自专栏我的博客

JavaScript获取高度和宽度

屏幕分辨率为:screen.width screen.height 屏幕可用大小:screen.availWidth screen.availHeight ...

2676
来自专栏SpiritLing

js获取页面宽高

网页可见区域宽:document.body.clientWidth 网页可见区域高:document.body.clientHeight 网页可见区域宽:doc...

2964

扫描关注云+社区