0

    一 计算界面原本滚动条的宽度

    2023.05.07 | admin | 251次围观

    界面无滚动

    滚动条的优化也有很多种只有进程没有界面,比如随便再网上搜索美化浏览器滚动条样式,就会出现些用css去美化滚动条的方案。

    那种更好呢?

    没有更好只有更合适

    那咱们就从无滚动条展开说说!!!

    无滚动条设计

    比如像element ui组件内像input的自定义模块数据过多的时候出现的下拉框内的滚动条,如下图

    在element-ui里面它其实是有内部组件el-scrollbar在的。那么它是怎么实现无滚动条呢?

    如下图咱们先把:hover勾选上让滚动条一直处于显示得状态。然后咱们再分析他的实现。

    当我把样式稍微修改下,咱们再观察下图:

    这么看是不是就很明白了 他其实用margin值把整个容器扩大了点然后溢出隐藏,其实滚动条还在就是给界面上看不到了而已。

    然后它自己用dom画了个滚动条,如下图:

    经过上面分析,咱们已经很清楚得了解到一个无滚动条是从那个方面实现得了。

    使用margin值把滚动条给溢出隐藏掉。使用div自己画了一个滚动条。方便咱们隐藏、显示、更改样式等。无滚动条实现

    那咱们再从细节上拆分下具体实现要考虑那些点:

    需要计算滚动条得宽度用来margin扩大得距离(每个界面上得滚动条得宽度是不一样得)。

    需要计算画的div滚动条得高度(这个内容多少会影响滚动条的高度)。

    需要根据滚动条去transform: translateY(19.3916%);移动咱们自己画的div滚动条的。

    需要根据摁着画的div滚动条,去实际更改需要滚动的高度。

    需要点击滚动轴的柱子支持跳到目标的滚动位置;一 计算界面原本滚动条的宽度

    计算下界面上原本滚动条的宽度如下:

    let scrollBarWidth;
    export default function() {
      if (scrollBarWidth !== undefined) return scrollBarWidth;
      const outer = document.createElement('div');
      outer.className = 'el-scrollbar__wrap';
      outer.style.visibility = 'hidden';
      outer.style.width = '100px';
      outer.style.position = 'absolute';
      outer.style.top = '-9999px';
      document.body.appendChild(outer);
      const widthNoScroll = outer.offsetWidth;
      outer.style.overflow = 'scroll';
      const inner = document.createElement('div');
      inner.style.width = '100%';
      outer.appendChild(inner);
      const widthWithScroll = inner.offsetWidth;
      outer.parentNode.removeChild(outer);
      scrollBarWidth = widthNoScroll - widthWithScroll;
      return scrollBarWidth;
    };
    复制代码

    先创建了一个div, 设置成scroll, 然后再在里面嵌套一个没有滚动条的div设置宽度100%, 获取到两者的offsetWidth, 相减获取到scrollBarWidth。赋值给scrollBarWidth 是惰性加载的优化,只需要计算一次就可以了。 具体展现如下图:

    二 计算画的滚动条的高度height

    计算下画的div滚动条的高度height。是用当前容器的内部高度 / 容器整个滚动条的高度 * 100计算出百分比;

    比如:

    const warp = this.$refs.wrap; // 或者使用documnet获取容器
    const heightPercentage = (wrap.clientHeight * 100 / wrap.scrollHeight); // height
    const widthPercentage = (wrap.clientWidth * 100 / wrap.scrollWidth); // width
    复制代码

    解析: 如当前容器高30px,内容撑起来总共高100px,那么滚动条的高度就是当前容器的30%;

    三 计算滚动条需要移动的值

    计算画的div需要滚动条的高度moveY是只有进程没有界面, 获取当前容器滚动的scrollTop / 当前容器内部高度 * 100:

    算法一:

    解析 使用transform: translateY(0%);是移动的是自己本身的百分比那么(容器滚动的scrollTop / 当前容器内部高度 * 100)算法如下:

    const warp = this.$refs.wrap; // 或者使用documnet获取容器
    this.moveY = ((wrap.scrollTop * 100) / wrap.clientHeight);
    this.moveX = ((wrap.scrollLeft * 100) / wrap.clientWidth);
    复制代码

    算法二:

    解析:使用定位top值,这个比较好理解滚动条的滚动 / 容器的滚动总高度 * 100得到百分比,如下:

    const warp = this.$refs.wrap; // 或者使用documnet获取容器
    this.moveY = ((wrap.scrollTop * 100) / wrap.scrollHeight);
    this.moveX = ((wrap.scrollLeft * 100) / wrap.scrollWidth);
    复制代码

    把计算出来的moveY、moveX的方法 绑定给scroll 滚动事件就可以了。

    四 摁着画的div滚动条 经行拖动

    滚动条都是支持拖着上下左右移动的,那咱们也要支持下:

    一个简单的拖动组件如下:

    
    
    
    复制代码

    咱们需要获取到画的滚动条的高度,然后根据拖动的距离算出来transform: translateY(0%);或者top值;

    如上面拖动组件 拖动部分代码就不在重复了 咱们直接用diffX、diffY、lastX、lastY来用了。

    算法一(transform)

    const thumb = document.querySelector('el-scrollbar__thumb'); // element ui  el-scrollbar 的滚动条
    const { height: thumbHeight } = thumb?.getBoundingClientRect() || {};
    const diffY = 10;
    const lastY = '300'; // transform: translateY(300%);`
    const moveY = (diffY / thumbHeight) + lastY;
    复制代码

    算法二(top)

    const thumb = document.querySelector('el-scrollbar__thumb'); // element ui  el-scrollbar 的滚动条
    const { height: thumbHeight } = thumb?.getBoundingClientRect() || {};
    const diffY = 10;
    const lastY = 30; // top: 30%`
    const moveY = (diffY / wrap.scrollWidth * 100) + lastY;
    复制代码

    五 点击滚动轴使滚动条跳转到该位置

    function clickTrackHandler(event) {
      const wrap = this.$refs.wrap;
      // 1. 减去clientX  正好能获取到需要滚动到的位置
     const offset = Math.abs(e.target.getBoundingClientRect().top - e.clientX);
     // 2. 利用offset 的到画的滚动条的实际位置 两种算法transform || top
      const thumb = document.querySelector('el-scrollbar__thumb'); // element ui  el-scrollbar 的滚动条
      const { height: thumbHeight } = thumb?.getBoundingClientRect() || {};
      const translateY = offset / height * 100; // transform 
      const top = offset / wrap.scrollHeight * 100; // top
      // 3、计算实际需要滚动的高度 使界面滚动到该位置。两种算法transform(scrollTop2) || top(scrollTop1)
      const scrollTop1 = top * wrap.scrollHeight; // top
      const scrollTop2 = translateY * wrap.clientHeight; // transform
    }
    复制代码

    总结

    针对无滚动条如果是vue使用的话,再了解具体实现后可以直接用element 的el-scrollbar组件就好,如果在其他框架中, 结合上面的逻辑也会很快封装一个组件。

    版权声明

    本文仅代表作者观点。
    本文系作者授权发表,未经许可,不得转载。

    发表评论