javascript实现自定义滚动条效果

在实际项目中,遇到上下滚动条和左右滚动条不在一个DIV内部,所以某些情况下,右侧滚动条不可见。但是需要咋同一个视口内显示两个滚动条。

一个解决思路是:自定义滚动条,隐藏原始滚动条。

自定义滚动条

scrollbar.js

import React, { Component } from 'react';
import PropTypes from 'prop-types';
import '../css/scrollbar.css';

const propTypes = {
  eventBus: PropTypes.object.isRequired,
};

class ScrollBar extends Component {

  constructor(props) {
    super(props);
    this.state = {
      isDraging: false,
      // X: bottom scrollbar offset left, range [0, innerWidth - 100]. When dragging, x is changing
      x: null,
      // clickX 表示拖动滚动条时,鼠标点击的位置距离滚动条左侧的距离, range [0, 100], When dragging, clickX isn't changing
      clickX: 0,
    };
  }

  componentDidMount() {
    this.unsubscribeScrollToColumn = this.props.eventBus.subscribe('set-scrollbar-left', this.setScrollBarLeft);
    document.addEventListener('mouseup', this.onMouseUp);
  }

  componentWillUnmount() {
    this.unsubscribeScrollToColumn();
    document.removeEventListener('mouseup', this.onMouseUp);
  }

  /**
   * 这个函数处理联动(界面滚动时,触发滚动条滚动)这里的100是滚动条的宽度
   */
  setScrollBarLeft = (leftRatio) => {
    // when bottom scrollbar is dragging, can't set scrollBa left
    if (this.state.isDraging) return;
    this.setState({
      x: (window.innerWidth - 100) * leftRatio,
    });
  }

  /**
   * 当鼠标按下,开始拖动,设置当前的位置为初始拖动的位置
   */
  handleMouseDown = (e) => {
    this.setState({
      isDraging: true,
      clickX: e.nativeEvent.offsetX,
    });
  }

  /**
   * 当鼠标抬起时,停止拖拽,设置当前的点击位置是0(这个有没有必要设置)
   */
  onMouseUp = () => {
    if (this.state.isDraging) {
      setTimeout(() => {
        this.setState({ isDraging: false, clickX: 0 });
      }, 100);
    }
  }

  /**
   * 当拖拽进行时(鼠标按下并开始移动),获取当前的位移,计算新的偏移量
   * 注意:可以向右滚动,可以向左滚动
   * 当拖拽进行时,应该计算出当前的比例,然后Grid水平滚动
   * 现在的问题,如果鼠标拖动时移动到滚动条外部,那么无法触发拖动
   * */
  onMouseMove = (e) => {
    e.persist();
    if (this.state.isDraging) {
      // 新距离 = 原始距离 + (当前滚动的距离 - 初始滚动的距离)
      let newX = this.state.x + e.nativeEvent.offsetX - this.state.clickX;
      newX = Math.min(newX, window.innerWidth - 100); // 最大的拖动不能超过右侧边界
      this.setState({ x: newX });
      const leftRatio = newX / (window.innerWidth - 100);
    }
  }

  renderBottomToolbar = () => {
    return (
      <div
        className="antiscroll-scrollbar antiscroll-scrollbar-horizontal antiscroll-scrollbar-shown"
        style={{transform: `translateX(${this.state.x}px)`}}
        draggable="true"
        onMouseDown={this.handleMouseDown}
        onMouseMove={this.onMouseMove}
        onMouseUp={this.onMouseUp}
      ></div>
    );
  }

  // todo: rightToolbar event handle
  renderRightToolbar = () => {
    return (
      <div
        className="antiscroll-scrollbar antiscroll-scrollbar-vertical antiscroll-scrollbar-shown"
      ></div>
    );
  }

  render() {
    return (
      <div id="scrollOverlay" className="antiscroll-wrap">
        {this.renderBottomToolbar()}
        {this.renderRightToolbar()}
      </div>
    );
  }
}

ScrollBar.propTypes = propTypes;

export default ScrollBar;

滚动条样式

对应的 scrollbar.css

#scrollOverlay {
  display: inline-block;
  overflow: hidden;
  position: fixed;
  left: 0;
  right: 0;
  top: 156px;
  bottom: 0;
  z-index: 4;
  pointer-events: none;
  opacity: .7;
}

#scrollOverlay .antiscroll-scrollbar {
  pointer-events: auto;
  z-index: 2;
  background-color: hsla(0,0%,0%,0.28);
  box-shadow: inset 0 0 0 1px hsl(0,0%,100%);
  border-radius: 5px;
}

#scrollOverlay .antiscroll-scrollbar-horizontal {
  height: 12px;
  width: 100px;
  position: absolute;
  bottom: 32px;
}

#scrollOverlay .antiscroll-scrollbar-vertical {
  width: 12px;
  height: 100px;
  position: absolute;
  right: 0;
}

/* 隐藏原始滚动对象的滚动条 */
.react-demo::-webkit-scrollbar {
  width: 0;
}

滚动条具体使用

具体使用,我们在 Grid 中加入这个滚动条

import ScrollBar from '../components/scrollbar';

// Grid 原生滚动,触发回调函数
onScroll = () => {
  // todo: when clientWidth is smaller than innerWidth, don't show bottom scrollBar
  let scrollLeftRatio = this._scrollLeft / (clientWidth - window.innerWidth);
  // 当原生DOM左右滚定时,获取当前滚动的比例(偏移量/全部宽度),并设置滚动条进行滚动
  this.setScrollLeftRatio(scrollLeftRatio);
}

setScrollLeftRatio = (scrollLeftRatio) => {
  this.props.eventBus.dispatch('set-scrollbar-left', scrollLeftRatio);
}

// 在原始滚动元素中,传入eventBus,便于事件传值处理
// <ScrollBar eventBus={this.props.eventBus}/>

自定义滚动条也有很多开源第三方组件,我们优先使用第三方库实现(处理滚动条计算考虑情况较多)

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • JS实现判断滚动条滚到页面底部并执行事件的方法

    需要了解三个dom元素,分别是:clientHeight.offsetHeight.scrollTop. clientHeight:这个元素的高度,占用整个空间的高度,所以,如果一个div有滚动条,那个这个高度则是不包括滚动条没显示出来的下面部分的内容.而只是单纯的DIV的高度. offsetHeight:是指元素内容的高度.依照上面的,那这个高度呢就是DIV内部的高度,包括可见部分及以滚动条下面的不可见部分. scrollTop:这个是什么呢?他可以理解为滚动条可以滚动的长度. 举例,如果一个

  • JavaScript限定范围拖拽及自定义滚动条应用(3)

    两个对象:div1 和 div2,其中div1是div2的父元素,div2只能在div1的范围内拖拽 图中,红点是鼠标的位置,两个绿色箭头相减的结果就是disX,最后oEvent.clientX - disX 就是绿色箭头的部分,这个长度就是判断是否"出格"的依据,也就是这个短的绿色箭头范围应该在0 ~ div2.offsetWidth - div1.offsetWidth之间! <!DOCTYPE html> <html> <head> <m

  • js操作滚动条事件实例

    本文实例讲述了js操作滚动条事件的方法.分享给大家供大家参考.具体分析如下: 之前一直很纳闷,如何监视滚动条的事件,今天终于有点明白了. 下边代码,是监听滚动条只要移动,下方的返回顶部的div显示与隐藏的代码 window.onscroll = function () { var t = document.documentElement.scrollTop || document.body.scrollTop; if (t > 0) { $(".cbbfixed").css(&q

  • 学习使用jquery iScroll.js移动端滚动条插件

    大家在日常工作中最常用的插件是什么,jQurey?Lazyload?但是这些都是在PC端,但是在移动端最常用的插件莫过于iScroll了,iScroll到底是什么东西,应该怎么用?iScroll是个很强大的插件,我也只是略懂皮毛,这里我们简单的介绍一下. iScroll的产生: iScroll的产生完全是因为移动版webkit浏览器,例如在iPhone,Android 的移动设备上. iScroll的使用方法: iScroll的原理是外层有一个溢出隐藏(overflow:hidden;)的DOM

  • js滚动条平滑移动示例代码

    本文实例为大家分享了js滚动条平滑移动相关代码,供大家参考,具体内容如下 html页 <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> <title></title> <script src="../Scripts/JavaScrip

  • js/jquery获取浏览器窗口可视区域高度和宽度以及滚动条高度实现代码

    获取浏览器窗口的可视区域高度和宽度,滚动条高度有需要的朋友可参考一下.IE中,浏览器显示窗口大小只能以下获取: 代码如下复制代码 复制代码 代码如下: document.body.offsetWidth document.body.offsetHeight 在声明了DOCTYPE的浏览器中,可以用以下来获取浏览器显示窗口大小: 代码如下复制代码 复制代码 代码如下: document.documentElement.clientWidth document.documentElement.cli

  • 判断滚动条到底部的JS代码

    判断滚动条到底部,需要用到DOM的三个属性值,即scrollTop.clientHeight.scrollHeight. scrollTop为滚动条在Y轴上的滚动距离. clientHeight为内容可视区域的高度. scrollHeight为内容可视区域的高度加上溢出(滚动)的距离. 从这个三个属性的介绍就可以看出来,滚动条到底部的条件即为scrollTop + clientHeight == scrollHeight. 废话不多少说,赶紧上代码(兼容不同的浏览器). 复制代码 代码如下: /

  • JS自定义滚动条效果简单实现代码

    本文实例为大家分享了JS自定义滚动条效果的具体代码,供大家参考,具体内容如下 <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>自定义滚动条</title> <style type="text/css"> #div1 { width: 20px; height: 400px; position: relative;

  • 原生JS实现自定义滚动条效果

    本文实例为大家分享了JS实现自定义滚动条的具体代码,供大家参考,具体内容如下 实现思路: 1.外层设置一个div,在外层的div里面设置一个特别高的div(高度为外层5个div的高度),在高的div里面设置5个div,每个div的高度,都和父级的高度相同 2.在外层div的右侧边框以里自定义一个滚动条,(本人用div设置样式作为滚动条) 3.最外层的div添加onmousewheel事件,使用e.wheelDelta来获取每次滑动的距离,若为正数则向上滑动,将每次增加的数,赋给滚动条的top值,

  • javaScript实现滚动条事件详解

    本文实例为大家分享了js实现滚动条事件的具体代码,供大家参考,具体内容如下 代码: <html> <head> <meta charset="utf-8"> <meta name="viewport" content="initial-scale=1.0, maximum-scale=1.0, user-scalable=no" /> <title></title> <

随机推荐