北川广海の梦

北川广海の梦

使用Better-Scroll快速给网页应用添加滚动栏

web
465
2020-07-16

滚动栏需求

网页中,为了流畅的信息展示,通过一个能够滚动的页面来展示,往往比分页对用户更加友好。并且需要用的到的场景非常多。例如我的mukai music中的播放列表,搜索结果,滚动歌词等等。
最初我为了实现滚动,纯粹使用JavaScript事件监听来实现,代码臃肿,并且自己造的轮子总是没那么圆。并且还有一些问题,例如移动端的触摸不能被监听到,也就无法完成滚动。
这里简单贴一下自己写的滚动代码引以为戒:

private initScroll() {
    let result_container = document.getElementById('result-container') as HTMLDivElement;
    let scroll = document.getElementById("r-scroll") as HTMLDivElement;
    let bar = document.getElementById("r-bar") as HTMLDivElement;
    let ul = document.getElementById("r-ul") as HTMLDivElement;

    //记录上一次滚动距离,用于鼠标滚动
    let oringin = 0;
    //拖动滚动条 内容滑动
    bar.onmousedown = function (e: MouseEvent) {

      //鼠标在滚动条中的位置
      let spaceY = e.clientY - bar.offsetTop;
      //2.2鼠标在页面上移动的时候,滚动条的位置
      document.onmousemove = function (e) {
        let y = e.clientY - spaceY;
        y = y < 0 ? 0 : y;
        y = y > scroll.offsetHeight - bar.offsetHeight ? scroll.offsetHeight - bar.offsetHeight : y;
        // 控制bar不能移除scroll
        oringin = y;
        bar.style.top = y + 'px';
        //3.当拖拽时,内容跟着滚动
        let offsetY = y * (ul.offsetHeight - result_container.offsetHeight) / (scroll.offsetHeight - bar.offsetHeight);
        ul.style.top = -offsetY + "px";
      }
    }
    document.onmouseup = function () {
      //移除鼠标移动事件
      document.onmousemove = null;
    }
    //设定是否允许鼠标滚动
    result_container.onmouseenter = (e: MouseEvent) => {
      this.allowScroll = true;
    }
    //设定是否允许鼠标滚动
    result_container.onmouseleave = (e: MouseEvent) => {
      this.allowScroll = false;
    }
    //鼠标滚轮滑动播放列表
    window.addEventListener('mousewheel', ((e: MouseWheelEvent) => {
      if (this.allowScroll) {
        oringin += e.deltaY / 5;
        //防止超出范围
        oringin = oringin < 0 ? 0 : oringin;
        oringin = oringin > scroll.clientHeight - bar.clientHeight ? scroll.clientHeight - bar.clientHeight : oringin;
        var barY = oringin;
        bar.style.top = barY + 'px';
        let offsetY = barY * (ul.offsetHeight - result_container.offsetHeight) / (scroll.offsetHeight - bar.offsetHeight);
        ul.style.top = -offsetY + "px";
      }
    }))
    let ul = document.getElementById("r-ul") as HTMLDivElement;
    let result_container = document.getElementById("result-container");
    let scroll = document.getElementById("r-scroll");
    let bar = document.getElementById("r-bar");
    let barHeight = 0;
    let visible = "hidden";
    this.allowScroll = false;
    barHeight = result_container.offsetHeight * scroll.offsetHeight / ul.offsetHeight;
    visible = "visible";
    this.allowScroll = true;
    bar.style.height = barHeight + "px";
    scroll.style.visibility = visible;
  }

Better-Scroll

betterScroll是一个开源的js滚动框库,目前在GitHub上获得了12.3K的star,
项目地址:https://github.com/ustbhuangyi/better-scroll
它的使用非常简单,两行代码就能让自己的区域变成滚动框,并且支持一些功能很强大的插件,例如scrollbar滚动条,mousewheel鼠标滚动,已经自动监听DOM的改变,来自动刷新scroll。用起来真的非常方便。
首先使用npm安装

npm install better-scroll

HTML页面,这是一个播放列表,注意让playlist-box的高度固定,让内容content的高度,随着内部元素撑高。

 <div id='playlist-box'>
        <div id="ul" class='content'>
            <li class="playlist-title" [id]="'playlist-item-'+i" *ngFor='let item of playlist;let i = index'>
                <div class='playlist-number'>
                    {{i+1}}
                </div>
                <div class='playlist-item'>
                    <div class='{{this.currentPlayIndex==i? themeClass:"playlist-name"}} playlist-name'>
                        <div class="item-name">
                            <span [title]='item.name'>{{item.name}}</span>
                        </div>
                        <div [id]="'option-'+i" class="playlist-options">
                            <mat-icon title="播放" class="click_button" (click)='clickPlay(i)'>play_circle_outline
                            </mat-icon>
                            <mat-icon title="下载" class="click_button" (click)='clickDownload(i)'>play_for_work
                            </mat-icon>
                            <mat-icon title="从列表删除" class="click_button" (click)='deleteMusic(i)'>delete</mat-icon>
                        </div>
                    </div>
                    <div class='playlist-artist'>
                        <span [title]='item.artists[0].name'>{{item.artists[0].name}}</span>
                    </div>
                    <div class='playlist-album'>{{item.album.name||"未知"}}</div>
                </div>
                <i></i>
            </li>
        </div>
    </div>
//引入BScroll和需要的插件
import BScroll from '@better-scroll/core';
import ScrollBar from '@better-scroll/scroll-bar'
import MouseWheel from '@better-scroll/mouse-wheel';
import ObserveDOM from '@better-scroll/observe-dom';

 ngOnInit() {
    //初始化scroll
    let wrapper = document.getElementById('playlist-box');
    //使用插件
    BScroll.use(MouseWheel);
    BScroll.use(ScrollBar);
    BScroll.use(ObserveDOM);
    //实例化并配置
    this.scroll = new BScroll(wrapper, {
      scrollY: true,
      click: true,
      mouseWheel: {
        speed: 20,
        invert: false,
        easeTime: 300
      },
      scrollbar: true,
      probeType: 3,
      observeDOM: true
    });
    //隐藏Scrollbar的边框
    let scrollbar = document.querySelector<HTMLDivElement>(".bscroll-indicator");
    scrollbar.style.border = 'none';
  }

效果:
image.png
并且支持鼠标滚轮,鼠标拖动,触摸拖动,并且添加了OberveDOM插件之后,能够自动在DOM改变之后,刷新Scroll,非常的方便。