组件源码——拖动条Slider

Slider主要的API如下:

属性类型说明
defaultValuenumber默认值
tickValuenumber标尺刻度数量,默认5
startnumber起始值,默认值为0
endnumber结束值
suffixstring后缀
onSlidingfunc滑块拖动进行时事件,value为拖动条当前值
onSlidfunc滑块拖动完成时事件,即鼠标抬起后执行,value为拖动条当前值

defaultValue就是默认的拖动条的位置,tickValue是有多少段,start和end分别是起始和结束刻度,suffix是后缀。

Slider组件的包括几个基础子组件:slider,selectedBar,Scale

slider是拖动的头部区域,就是那个方块和tooltip

selectedBar是蓝色区域,不包括slider,是已选择的区域

Scale是下面的刻度区域

bar是整个的灰色线条区域

刻度:

刻度的实现就是创建一个数组,用来存储每个刻度div(一个刻度就是一个div),然后通过遍历来给每一个刻度赋值(value)和给style.left赋值,这样刻度条按照特定的位置排列。

class Scale extends Component {
  constructor() {
    super()
  }
  componentWillMount() {
    this.tickValue = this.props.tickValue || 5
  }
  render() {
    const {width} = this.props

    const rows = []
    for (let i = 0; i <= this.tickValue; i++) {
      rows.push(<div key={i} ref={'t' + i} className="bfd-scale__tick">
        <div></div>
        {i}</div>)
    }
    return (
      <div ref="container" style={{width}} className={classnames('bfd-scale', this.props.className)}>
        {rows}
      </div>
    )
  } 
  componentDidMount() {
    const container = this.refs.container
    const containerStyle = getComputedStyle(container)
    const width = parseInt(containerStyle.width)
    const scope = this.props.end - (this.props.start || 0)
    this.width = width
    this.scope = scope
    const arr = this.getTick(this.tickValue)
    arr.map((tick, index) => {
      let value = scope / width * tick + this.props.start
      if (index == 0) {
        value = this.props.start
      }
      if (index == arr.length - 1) {
        value = this.props.end
      }

      const el = this.refs['t' + index]
     s el.innerHTML = '<div></div>' + parseInt(Math.round(value))
      if (index == 0) {
        el.style.left = 4 + 'px'
      } else if (index == this.tickValue) {
        el.style.left = parseInt(tick) - 1 + 'px'
      } else {
        el.style.left = tick + 'px'
      }
    })
  }

  getTick(num) {
    const arr = []
    num = !num ? 1 : num
    const w = this.width / num
    for (let i = 0; i < num; i++) {
      arr.push(i * w)
    }
    arr.push(this.width)``

    return arr
  }
}
复制代码

slider区域

slider区域是整个组件逻辑所在的地方,主要是该组件绑定了mouseDown事件,而mousedown事件中为body绑定了mousemove和mouseup事件,我们的逻辑主要在mousemove事件中,在mousedown事件和mouseup事件响应函数中主要是为body注册和卸载事件监听器。我们来看mousemove事件的监听函数:

handleMouseMove(event) {
    const slider = this.refs.slider
    const selectedBar = this.refs.selectedBar
    const bar = this.refs.bar

    this.offsetLeft = this.getOffsetLeft(bar) + this.marginLeft
    if (this.isDown) {
      let left = event.pageX - this.offsetLeft - this.sliderWidth / 4
      if (left <= 0) {
        left = 0
        selectedBar.style.width = left + 'px'
      } else if (left >= (this.width - this.sliderWidth / 2)) {
        left = this.width - this.sliderWidth / 2
        selectedBar.style.width = this.width + 'px'
      } else {
        selectedBar.style.width = left + 'px'
      }
      slider.style.left = left + 'px'
      const text = this.getValue(parseInt(selectedBar.style.width, 10))
      this.refs.msg.innerHTML = text + (this.props.suffix || '')
      if (typeof this.props.onSliding == 'function') {
        this.props.onSliding(text)
      }
    }
  }
复制代码

可以看到,上面主要是设置selectBar的宽度selectedBar.style.width,设置msg中的文本text,如果组件设置了onSiding处理函数的话,就触发该函数。

代码中有一个封装较好的函数,用来获取一个元素的左偏移量

getOffsetLeft(el) {
    let left = 0
    let offsetParent = el
    while (offsetParent != null && offsetParent != document.body) {
      left += offsetParent.offsetLeft
      offsetParent = offsetParent.offsetParent
    }
    return left
  }
复制代码
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值