自定义滚动条

代码效果:

See the Pen vYxvXPb by 梁什么鸭“ ( @liang-duck) on CodePen.

拖动滚动条

oSpan.onmousedown = function (e) {
          e = e || window.event;

		// 记录点击滚动块时,鼠标的坐标和滚动块oSpan的left 和 top
		// 因为滚动块只需要上下移动,所以就不用记录 x坐标 和 滚动块oSpan的 left
          const contentTop = oContent.offsetTop;
          const spanTop = oSpan.offsetTop;
          const downY = e.clientY;

		// 阻止冒泡
          e.stopPropagation();

          document.onmousemove = function (e) {
            e = e || window.event;

			// 记录鼠标移动时的坐标
            const moveY = e.clientY;
            // 记录鼠标移动了的距离
            const deferY = moveY - downY;
            // 使滚动块也移动同样的距离
            let _y = spanTop + deferY;
            // 内容相对滚动块移动的距离比例
            let _cy = contentTop - deferY * gap_box;

			// 设置滚动块移动的范围
            if (_y >= gap_scroll) {
              oSpan.style.top = gap_scroll + 'px';
              oContent.style.top = -gap_content + 'px';

            }
            else if (_y <= 0) {
              oSpan.style.top = 0;
              oContent.style.top = 0;
            }
            else {
              oSpan.style.top = _y + 'px';
              oContent.style.top = _cy + 'px';
            }

          };
        };
        // 当鼠标抬起的时候,清除鼠标移动事件
        document.onmouseup = function () {
          document.onmousemove = null;
        }

示图:
在这里插入图片描述

滚动块的距离 : 滚动块不超过滚动条的顶部和底部,
即滚动块 0 ≤ top ≤ oScroll.offsetHeight - oSpan.offsetHeight

内容盒子的滚动距离:当滚动块拖到最底部的时候,内容盒子刚好显示完,所以内容盒子滚动的距离和滚动块滚动的距离是成比例的。 内容盒子的高度是动态的,一般习惯用动态的盒子比上静态的盒子。
所以比例为 :
(oContent.offsetHeight - oBox.offsetHeight ) / (oScroll.offsetHeight - oSpan.offsetHeight )

滚轮滚动

mousewheel(oBox, function (e) {
          e = e || window.event;

          const scrollTop = oSpan.offsetTop;
          let val;
          const speed = 5;  // 设置滚动条随滚轮滚动而移动的速度

		// 当滚轮向前滚,滚动块向上移动
          if (e.wheelDetail > 0) {
            val = scrollTop - speed;
          }else {  //  当滚轮向后滚,滚动块向下移动
            val = scrollTop + speed;
          }
          compare(val);

        }, true);
      }

    
   // 设置滚动块随滚轮 滚动的距离范围
      function compare(val) {
        val = max(0, val);  // 0 和 val 中取最大的那个
        val = min(gap_scroll, val);  //  gap_scroll 和 val 中取最小的那个, gap_scroll是滚动条和滚动块的差

        const bili = val / gap_scroll;  //  记录滚动块 滚动了的距离 闭比上 滚动块的滚动范围
        const contentTop = bili * gap_content;  // 设置内容盒子移动距离占 可移动范围的 比例

        oSpan.style.top = val + 'px';
        oContent.style.top = -contentTop + 'px';
      }

图示:
在这里插入图片描述

点击滚动条,使滚动块移动到点击的位置

一般是使滚动块的中间位置移动到鼠标点击滚动条的位置

当在滚动块点击,滚动块不移动。只有在滚动条上点击才移动

oScroll.onclick = function (e) {
          e = e || window.event;

          const that = e.target;
          if(that !== this) return ; // 事件代理,判断是否在scroll上点击了

          // 在scroll上点击了
          /*let clickTop = e.clientY - oSpan.offsetHeight / 2;
          clickTop = max(0, clickTop); // 当span的top小于0时,clickTop=0
          clickTop = min(gap_scroll, clickTop); // 当span的top大于gap_scroll时,clickTop=gap_scroll
          oSpan.style.top = clickTop + 'px';
          oContent.style.top = -(oSpan.offsetTop / gap_scroll * gap_content) + 'px';*/
          // 以上代码没有考虑到一个问题:
          // 鼠标获取的是在可视区的y位置,这里box的left top都是0,所以这里的运行结果没错,
          // 假设有个divA包着box这个div,且box以A 为定位标准,假设left top都为100,那么这时运行结果就出错了
          // 就这段代码 : let clickTop = e.clientY - oSpan.offsetHeight / 2;
          // 要想点击scroll上相同的位置,那么此时e.clientY就增加了 100,
          // 那么clickTop 就不再是期待得到的值,而比期待值大 100

          // let val = e.clientY - this.getBoundingClientRect() - oSpan.offsetHeight / 2;  // 不兼容IE
          let val = e.pageY - getDoc(this).top - oSpan.offsetHeight / 2;
          compare(val);

        }

一个相对定位的问题

就以上有问题的代码来说:

let clickTop = e.clientY - oSpan.offsetHeight / 2;
          clickTop = max(0, clickTop); // 当span的top小于0时,clickTop=0
          clickTop = min(gap_scroll, clickTop); // 当span的top大于gap_scroll时,clickTop=gap_scroll
          oSpan.style.top = clickTop + 'px';

以上代码的思路:
鼠标在滚动条上点击,
滚动块中间的位置等鼠标点击的位置

在这里插入图片描述
在这种情况是可行的,
因为滚动条和鼠都是相对 body定位的
鼠标的 clientX 和 clientY 和
滚动块的 offsetLeft 和 offsetTop
是一致的

在这里插入图片描述

假设滚动条高度为200px , 以body为定位标准,left=100 top=100
而滚动块高度为30px ,还是相对滚动条定位

那么此时当鼠标在滚动条上点击,
假设鼠标在滚动条的中间位置点击,此时鼠标的clientY = 200
按照以上代码的思路,oSpan.offsetTop = 200 - (oSpan.offsetHeight/2)=185
因为oSpan是相对滚动条定位的,所以它会移动到下面的位置
在这里插入图片描述
所以滚动块的top 等于 鼠标的位置 - 定位的距离
在这里插入图片描述

let val = e.pageY - getDoc(this).top - oSpan.offsetHeight / 2;

有可能多个盒子嵌套定位:
在这里插入图片描述
也就是说要减去 各盒子的定位距离和:

// 叠加每级间的定位距离,知道加到body
      function getDoc(ele) {
        const obj = {
          top: 0,
          left: 0
        }
        while (ele !== document.body) {
          obj.left += ele.offsetLeft;
          obj.top += ele.offsetTop;

          ele = ele.offsetParent;
        }
        return obj;
      }
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

梁什么鸭,

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值