Slider主要的API如下:
属性 | 类型 | 说明 |
---|---|---|
defaultValue | number | 默认值 |
tickValue | number | 标尺刻度数量,默认5 |
start | number | 起始值,默认值为0 |
end | number | 结束值 |
suffix | string | 后缀 |
onSliding | func | 滑块拖动进行时事件,value为拖动条当前值 |
onSlid | func | 滑块拖动完成时事件,即鼠标抬起后执行,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
}
复制代码