• 音量调节条-封装通用的ProgressBar组件


    import React, { Component } from 'react'
    import PropTypes from 'prop-types'
    import assign from 'object-assign'
    import _ from 'lodash'
    import CX from 'classnames'
    
    import './index.less'
    
    /**
     * ProgressBar
     * vertical 设置进度条是否垂直显示
     * trackHover trackHover事件
     * onSlide 事件函数获取percent值
     * percent 设置滑块位置,0~100之间
     * style 最外层div的样式
     * slidedStyle 滑块左侧划过部分的样式
     * trackStyle 滑块右侧未划过部分的样式
     * ballStyle 滑块的样式
     * showHoverStyle 是否设置hover时的样式
     * hoverStyle 最外层div的样式
     * hoverSlidedStyle 滑块左侧划过部分的样式
     * hoverTrackStyle 滑块右侧未划过部分的样式
     * hoverBallStyle 滑块的样式
     * dragInfo 滑动滑块时显示在滑块上方的提示信息,默认没有提示信息
     * dragInfoWrapStyle 滑块提示信息父级元素的样式,可用于调整提示信息的位置
     * previewInfo 指针在进度条内时显示的指针位置进度提示信息
     * previewInfoWrapStyle previewInfo 提示信息父级元素的样式,可用于调整提示信息的位置
     * onCursorSlide 事件函数获取当前指针处的percent 可用于更新previewInfo
     */
    
    class ProgressBar extends Component {
      static propTypes = {
        vertical: PropTypes.bool,
        onSlide: PropTypes.func,
        style: PropTypes.object,
        slidedStyle: PropTypes.object,
        trackStyle: PropTypes.object,
        ballStyle: PropTypes.object,
        showHoverStyle: PropTypes.bool,
        hoverStyle: PropTypes.object,
        hoverSlidedStyle: PropTypes.object,
        hoverTrackStyle: PropTypes.object,
        hoverBallStyle: PropTypes.object,
        percent: PropTypes.number,
        dragInfo: PropTypes.element,
        dragInfoWrapStyle: PropTypes.object,
        previewInfo: PropTypes.element,
        previewInfoWrapStyle: PropTypes.object,
        onCursorSlide: PropTypes.func,
        disableSlide: PropTypes.bool,
      }
    
      static defaultProps = {
        vertical: false,
        onSlide: _.noop,
        style: {},
        slidedStyle: {},
        trackStyle: {},
        ballStyle: {},
        showHoverStyle: false,
        hoverStyle: {},
        hoverSlidedStyle: {},
        hoverTrackStyle: {},
        hoverBallStyle: {},
        percent: 0,
        dragInfo: null,
        dragInfoWrapStyle: {},
        previewInfo: null,
        previewInfoWrapStyle: {},
        onCursorSlide: _.noop,
        disableSlide: false,
      }
    
      state = {
        percent: this.props.percent,
        cursorPercent: 0,
        moveFlag: false,
        cursorInSlideBall: false,
        cursorInComponent: false,
      }
    
      componentDidMount() {
        this.rangeSlideElem.addEventListener('mousedown', this.onWrapElemMouseDown)
        this.rangeSlideElem.addEventListener('mouseenter', this.onWrapElemMouseEnter)
        this.rangeSlideElem.addEventListener('mousemove', this.onWrapElemMouseMove)
        this.rangeSlideElem.addEventListener('mouseleave', this.onWrapElemMouseLeave)
        this.rangeSlideElem.addEventListener('click', this.handleSlide)
    
        document.body.addEventListener('mousemove', this.onBodyMouseMove)
        document.body.addEventListener('mouseup', this.onBodyMouseUp)
        document.body.addEventListener('mouseleave', this.onBodyMouseLeave)
      }
    
      componentWillReceiveProps(nextProps) {
        if (nextProps.percent !== this.props.percent) {
          this.setState({
            percent: nextProps.percent,
          })
        }
      }
    
      componentWillUnmount() {
        document.body.removeEventListener('mousemove', this.onBodyMouseMove)
        document.body.removeEventListener('mouseup', this.onBodyMouseUp)
        document.body.removeEventListener('mouseleave', this.onBodyMouseLeave)
      }
    
      getPercent = (e) => {
        let percentage
        if (this.props.vertical === false) {
          const offsetLeft = this.rangeSlideElem.getBoundingClientRect().x
          const { offsetWidth } = this.rangeSlideElem
          percentage = Math.round(((e.pageX - offsetLeft) / offsetWidth) * 100)
        } else {
          const offsetTop = this.rangeSlideElem.getBoundingClientRect().y
          const { offsetHeight } = this.rangeSlideElem
          percentage = Math.round((1 - (e.pageY - offsetTop) / offsetHeight) * 100)
        }
        percentage = Math.max(Math.min(percentage, 100), 0)
    
        return percentage
      }
    
      onWrapElemMouseDown = () => {
        this.setState({
          moveFlag: true,
        })
      }
    
      onBodyMouseMove = _.throttle((e) => {
        if (this.state.moveFlag) {
          this.handleSlide(e)
        }
      }, 30)
    
      onBodyMouseUp = () => {
        this.setState({
          moveFlag: false,
        })
      }
    
      onBodyMouseLeave = this.onBodyMouseUp
    
      handleSlide = (e) => {
        if (this.props.disableSlide === true) {
          return
        }
        const percent = this.getPercent(e)
        this.props.onSlide(percent)
        this.setState({
          percent,
        })
      }
    
      onSlideBallMouseEnter = () => {
        this.setState({
          cursorInSlideBall: true,
        })
      }
    
      onSlideBallMouseLeave = () => {
        this.setState({
          cursorInSlideBall: false,
        })
      }
    
      onWrapElemMouseEnter = (e) => {
        const cursorPercent = this.getPercent(e)
        this.props.onCursorSlide(cursorPercent)
        this.setState({
          cursorInComponent: true,
          cursorPercent,
        })
      }
    
      onWrapElemMouseMove = (e) => {
        const cursorPercent = this.getPercent(e)
        this.props.onCursorSlide(cursorPercent)
        this.setState({
          cursorPercent,
        })
      }
    
      onWrapElemMouseLeave = () => {
        this.setState({
          cursorInComponent: false,
        })
      }
    
      rangeSlideElem
    
      activeBarElem
    
      render() {
        const { cursorInComponent } = this.state
        const showHoverStyle = cursorInComponent && this.props.showHoverStyle
        const wrapStyles = assign({}, showHoverStyle ? this.props.hoverStyle : this.props.style)
        let slideTrackStyles
        if (this.props.vertical === true) {
          slideTrackStyles = assign({}, showHoverStyle ? this.props.hoverTrackStyle : this.props.trackStyle, {
            height: `${100 - this.state.percent}%`,
          })
        } else {
          slideTrackStyles = assign({}, showHoverStyle ? this.props.hoverTrackStyle : this.props.trackStyle, {
             `${100 - this.state.percent}%`,
          })
        }
        const activeBarStyles = assign({}, showHoverStyle ? this.props.hoverSlidedStyle : this.props.slidedStyle)
        const slideBallStyles = assign({}, showHoverStyle ? this.props.hoverBallStyle : this.props.ballStyle)
        const dragInfoWrapStyle = assign({}, this.props.dragInfoWrapStyle)
        const previewInfoWrapStyle = assign({}, this.props.previewInfoWrapStyle, {
          left: `${this.state.cursorPercent}%`,
        })
        const showDragInfo = this.state.cursorInSlideBall || this.state.moveFlag
        const showPreviewInfo = showDragInfo === false && this.state.cursorInComponent
    
        return (
          <div
            className={CX({
              'horizontal-progress-bar-component-wrap': this.props.vertical === false,
              'vertical-progress-bar-component-wrap': this.props.vertical === true,
            })}
            style={wrapStyles}
            ref={(r) => {
              this.rangeSlideElem = r
            }}
          >
            <div className="active-bar" style={activeBarStyles} />
            <div
              className="slide-track"
              ref={(r) => {
                this.activeBarElem = r
              }}
              style={slideTrackStyles}
            >
              <div
                className="slide-ball"
                style={slideBallStyles}
                onMouseEnter={this.onSlideBallMouseEnter}
                onMouseLeave={this.onSlideBallMouseLeave}
              />
              {
                showDragInfo && (
                  <div
                    className="drag-info-element-wrap"
                    style={dragInfoWrapStyle}
                  >
                    {this.props.dragInfo}
                  </div>
                )
              }
            </div>
            {
              showPreviewInfo && (
                <div
                  className="preview-info-element-wrap"
                  style={previewInfoWrapStyle}
                >
                  {this.props.previewInfo}
                </div>
              )
            }
          </div>
        )
      }
    }
    
    export default ProgressBar

    样式如下:

    .horizontal-progress-bar-component-wrap {
      width: 100%;
      height: 12px;
      margin: 0;
      position:relative;
      cursor: pointer;
    
      .active-bar {
        position:absolute;
        top: 50%;
        left: 0;
        margin-top: -2px;
        width: 100%;
        height: 4px;
        border-radius: 4px;
        background: linear-gradient(to right, #81d5fa, #3977f6);
      }
      .slide-track {
        width: 50%;
        height: 4px;
        position:absolute;
        top: 50%;
        right: 0;
        margin-top: -2px;
        border-radius: 4px;
        background: #fff;
    
        .slide-ball {
          width: 12px;
          height: 12px;
          position: absolute;
          left: -6px;
          top: -4px;
          border-radius: 50%;
          cursor: pointer;
          background: url('~ROOT/shared/assets/image/vn-circle-blue-42-42.png') no-repeat center;
          background-size: 12px;
        }
        .drag-info-element-wrap {
          position: absolute;
          left: -24px;
          top: -46px;
        }
      }
    
      .preview-info-element-wrap {
        position: absolute;
        top: -32px;
        margin-left: -24px;
      }
    }
    
    .vertical-progress-bar-component-wrap {
      width: 12px;
      height: 100%;
      margin: 0;
      position: relative;
      cursor: pointer;
    
      .active-bar {
        position:absolute;
        bottom: 0;
        left: 50%;
        margin-left: -2px;
        height: 100%;
        width: 4px;
        border-radius: 4px;
        background: linear-gradient(to top, #81d5fa, #3977f6);
      }
      .slide-track {
        position:absolute;
        height: 50%;
        width: 4px;
        right: 50%;
        top: -2px;
        margin-right: -2px;
        border-radius: 4px;
        background: #fff;
    
        .slide-ball {
          width: 12px;
          height: 12px;
          position: absolute;
          left: -4px;
          bottom: -6px;
          border-radius: 50%;
          cursor: pointer;
          background: url('~ROOT/shared/assets/image/vn-circle-blue-42-42.png') no-repeat center;
          background-size: 12px;
        }
        .drag-info-element-wrap {
          position: absolute;
          left: -46px;
          bottom: -24px;
        }
      }
    
      .preview-info-element-wrap {
        position: absolute;
        left: -32px;
        margin-bottom: -24px;
      }
    }
  • 相关阅读:
    迷你资源管理器
    简单工厂和单例的一些事
    面向对象的七大原则
    继承和多态的一些事
    体检套餐系统
    信仰
    魔兽争霸系统
    优化MySchool总结习题
    事务,视图及索引
    [LeetCode] Combinations
  • 原文地址:https://www.cnblogs.com/chenbeibei520/p/11465559.html
Copyright © 2020-2023  润新知