在实际项目中,遇到上下滚动条和左右滚动条不在一个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}/>

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

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

javascript实现自定义滚动条效果的更多相关文章

  1. html5 拖拽及用 js 实现拖拽功能的示例代码

    这篇文章主要介绍了html5 拖拽及用 js 实现拖拽,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

  2. h5页面背景图很长要有滚动条滑动效果的实现

    这篇文章主要介绍了h5页面背景图很长要有滚动条滑动效果的实现,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

  3. amaze ui 的使用详细教程

    这篇文章主要介绍了amaze ui 的使用详细教程,本文通过多种方法给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

  4. ios – 如何在UICollectionView上始终显示滚动条

    我在我正在处理的应用程序中添加了一个UICollectionView到UIView.在UICollectionView中显示我有一组从CoreData中提取的图像.垂直滚动工作正常但滚动条不会显示,直到用户触摸UICollectionView.如何确保右侧的滚动条始终可见,以便向用户指示它是否可滚动?

  5. swift UI专项训练38 用代码实现滚屏ScrollView

    有时候我们在一个页面中放不下所有内容,就需要用到ScrollView,多余的内容可以通过滚动来获取。然后在viewDidLoad中初始化一个scrollView:要想实现滚屏,pagingEnabled必须设为true。我们先把它设为true看看效果,别忘了把这个scrollView显示到页面中:然后我们把需要的内容加到这个scrollView中,例如增加一个标题:运行一下看看效果因为我们把scrollView的尺寸设定为高800,超出屏幕的高度,我们向下拖动,注意右侧出现的滚动条:然后继续添加需要的内容

  6. swift皮筋弹动发射飞机ios源码

    这是一个款采用swift实现的皮筋弹动发射飞机游戏源码,游戏源码比较详细,大家可以研究学习一下吧。

  7. Swift - 将表格UITableView滚动条移动到底部

    有时我们需要通过代码自动将表格UITableView滚动条移动到尾部,只需要使用scrollToRowAtIndexPath方法即可,代码如下:12345varsecon=1//最后一个分组的索引(0开始,如果没有分组则为0)rows=5//最后一个分组最后一条项目的索引indexPath=NSIndexPath(forRow:rows,inSection:secon)self.tableView

  8. Swift与Js通过WebView交互

    开发环境:Swfit2.3XCode8.2基础概念jscontext,jscontext是代表JS的执行环境,通过-evaluateScript:方法就可以执行一JS代码JSValue,JSValue封装了JS与ObjC中的对应的类型,以及调用JS的API等JSExport,JSExport是一个协议,遵守此协议,就可以定义我们自己的协议,在协议中声明的API都会在JS中暴露出来,才能调用Swif

  9. JSCore swift

    如果双方相互引用,会造成循环引用,而导致内存泄露。以上是Jscore的基本使用,比较简单

  10. Swift WKWebView的js调用swift

    最近项目需求,需要用到JavaScriptCore和WebKit,但是网上的资源有限,而且比较杂,都是一个博客复制另外一个博客,都没有去实际敲代码验证,下面给大家分享一下我的学习过程。

随机推荐

  1. js中‘!.’是什么意思

  2. Vue如何指定不编译的文件夹和favicon.ico

    这篇文章主要介绍了Vue如何指定不编译的文件夹和favicon.ico,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

  3. 基于JavaScript编写一个图片转PDF转换器

    本文为大家介绍了一个简单的 JavaScript 项目,可以将图片转换为 PDF 文件。你可以从本地选择任何一张图片,只需点击一下即可将其转换为 PDF 文件,感兴趣的可以动手尝试一下

  4. jquery点赞功能实现代码 点个赞吧!

    点赞功能很多地方都会出现,如何实现爱心点赞功能,这篇文章主要为大家详细介绍了jquery点赞功能实现代码,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  5. AngularJs上传前预览图片的实例代码

    使用AngularJs进行开发,在项目中,经常会遇到上传图片后,需在一旁预览图片内容,怎么实现这样的功能呢?今天小编给大家分享AugularJs上传前预览图片的实现代码,需要的朋友参考下吧

  6. JavaScript面向对象编程入门教程

    这篇文章主要介绍了JavaScript面向对象编程的相关概念,例如类、对象、属性、方法等面向对象的术语,并以实例讲解各种术语的使用,非常好的一篇面向对象入门教程,其它语言也可以参考哦

  7. jQuery中的通配符选择器使用总结

    通配符在控制input标签时相当好用,这里简单进行了jQuery中的通配符选择器使用总结,需要的朋友可以参考下

  8. javascript 动态调整图片尺寸实现代码

    在自己的网站上更新文章时一个比较常见的问题是:文章插图太宽,使整个网页都变形了。如果对每个插图都先进行缩放再插入的话,太麻烦了。

  9. jquery ajaxfileupload异步上传插件

    这篇文章主要为大家详细介绍了jquery ajaxfileupload异步上传插件,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  10. React学习之受控组件与数据共享实例分析

    这篇文章主要介绍了React学习之受控组件与数据共享,结合实例形式分析了React受控组件与组件间数据共享相关原理与使用技巧,需要的朋友可以参考下

返回
顶部