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

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

本文主要内容

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 条评论
登录 后参与评论

相关文章

来自专栏我分享我快乐

一线UI设计师对APP切图尺寸换算指导

工作后,很多同学还是会问到app切图尺寸的问题。今天分享android和iOS的换算分析,希望能帮到工作中的你。 1.在Android的显示模式为mdpi的时...

34514
来自专栏冷冷

jqGrid 关闭刷新父页面数据

子页面提交方法: function commit(){     var data = $("#pwd").serialize();     $.post("#...

20210
来自专栏大数据钻研

你不得不了解的HTML知识

这次要细说的只是块级元素和行内元素的内容,如有不对,请轻喷。 块级元素和行内元素 默认情况下块级元素会始终占居一行,而行内元素并不会。除了 table 元素的 ...

2656
来自专栏Golang语言社区

JavaScript Window - 浏览器对象模型

浏览器对象模型 (BOM) 使 JavaScript 有能力与浏览器“对话”。 浏览器对象模型 (BOM) 浏览器对象模型(Browser Object Mod...

3733
来自专栏前端知识分享

第138天:Web前端面试题总结(编程)

2、一个页面上两个div左右铺满整个浏览器,要保证左边的div一直为100px,右边的div跟随浏览器大小变化(比如浏览器为500,右边div为400,浏览器为...

733
来自专栏计算机编程

SNS项目笔记<三>--fab与遮罩

<b>在项目界面搭建过程中,使用fab的时候发现ionic自带的控件中并没有遮罩这样的属性这让我们实际操作起来很不舒服如下图所示:

714
来自专栏Bingo的深度学习杂货店

水平居中和垂直居中

本章介绍几种常见的水平居中和垂直居中的实现方式 <!DOCTYPE html> <html> <head> <title>水平居中和垂直居中</titl...

2853
来自专栏有趣的django

18.CSS

选择器 1.标签上直接设置style属性 <p style="color: red">直接标签里面写</p> 2.id选择器 <style> ...

3237
来自专栏ShaoYL

iOS---设置控件的内容模式

34112
来自专栏C/C++基础

web前端开发初学者十问集锦(2)

行内元素(如a标签),在文档流中的时候因为是行内元素所以无法设置宽高;而当设置了绝对定位或者浮动,会生成块级框(即变成块级元素),所以就可以设置宽高了。

691

扫码关注云+社区