【为什么】要在Windows浏览器实现Mac OS上滚动条的效果?

1,696 阅读3分钟

写在前面

为什么要优化windows上的滚动条?

众所周知,相较于Mac OS系统,Windows系统的滚动条可以谓之一个丑字。

没有对比,就没有伤害

为什么要按Mac OS上滚动条的效果来实现?

Windows上的滚动条又宽又长还固定占位置,容易挤压内容展示区域。Mac OS浏览器上的滚动条默认是不展示的,只有在滑动时才展示,而且是半透明不占内容展示位置的

命中注定,有次一劫

总结需求:

  • 样式美化
  • 只在滑动时展示滚动条
  • 滚动条不占内容空间

实现方案

经过一番搜索得到两个主流方案:

  • CSS方案 —— 能满足第一点,不能满足第二第三点;
  • JS插件方案,例如iscroll系列——可以满足全部需求;

iscroll系列包含以下三个插件,他们层层封装,最后一个难度最小,盘它。

虽然react-with-better-scroll的star比较少,翻看了源码还比较靠谱,推荐一下;

另外注意npm包名和项目的区别,npm命令是:

npm i react-with-better-scroll --save

代码实现

BetterScroll主要针对h5手机浏览器,Github仓库示例也展示的是下拉刷新/上拉加载更多功能的实现,该功能默认也是打开的,这对前端稍为就不那么友好,不过这并不影响使用,那么我们就参考API文档自己动手来DIY吧。

<BetterScrollList
  bscrollListRef={bsListInstance} // useRef
  scrollbar={{ fade: true }} // 启用默认隐藏
  options={{
    mouseWheel: true, // 支持鼠标滚轮事件
    bounce: false, // 关闭回弹动画
    momentum: false, // 快速滑动回弹
  }}
>
  <ul>
    {items.map((item, index) => (
      <li key={item.id} className="item">{index}</li>
    ))}
  </ul>
</BetterScrollList>

因为react-with-better-scroll是对better-scroll的封装,所以核心配置options还是要查找better-scroll的文档,这里记录下最新的文档地址:

跳坑指南

  1. react-with-better-scroll项目 地址不好找,着急的时候容易上火;
  • 项目名和npm包名不一致
  • 同名项目也比较多
  1. better-scroll文档地址不好找,最上面的中文文档地址,跳转到README中文版就有点让人着急,推荐点击2.xDocs或者右侧上方的文档地址,然后切换语言到中文就可以查看中文文档了。

上面两条坑点也是调侃,可能因为我经常清理浏览器Tab页,老是需要重新找文档,所以有点不愉快。下面记录技术上的一些耗时点:

  1. 关闭下拉上拉动画:只看上面的作用介绍还以为这个api只是控制动画的部分,而我需要关闭整个功能,所以反复多次翻阅文档,最后终于发现下图位置的可以关闭的说明,害我好找。

image.png

可是即便是bounce设置成false也并没有完全取消掉下拉/上拉动画效果,快速滚动,下拉幅度还是很大,不符合前端需;后面继续查看文档才发现还有个快速的下拉/上拉的动画效果。🥵🥵🥵

image.png

...
options={{
  bounce:false,
  momentum:false,
}}
...

至此才算彻底关闭掉了上拉/下拉效果,这是第一个技术坑。

  1. 第二个是动态更新滑动区域的内容时,滚动条不能及时计算内容高度,出现内容多不能滑动,内容少却可以滑动的尴尬情况... 翻阅文档后发现refresh方法正中下怀: image.png 于是在setData更新内容区域后,调用refresh方法重新计算内容高度;正当我满心欢喜的时候,滚动条还是滞后一次出现😩,难道是我姿势不对?不!不!不...最后居然想起了延时大法,真是好用!

这里😏想歪的😏请自觉到评论区排队哈,我看到你了!

const betterScrollDelayRefresh = () => {
  if (bsListInstance?.current) {
    setTimeout(() => {
      bsListInstance?.current?.refresh();
    }, 50);
  }
};

这里使用的是React Hooks的useRef,使用.current获取实例对象;

最后这是使用setTimeOut也实属无奈,还请各位掘友指正。 至此本猿终于躲过这一劫,完美实现产品三个功能点。