UNPKG

jimu-mobile

Version:

积木组件库助力移动端开发

268 lines (236 loc) 7.79 kB
/** * Created by yanshenshen on 17/04/10. */ import React from 'react'; import classNames from 'classnames'; import PropTypes from 'prop-types'; class Slider extends React.Component { static propTypes = { max: PropTypes.number, min: PropTypes.number, defaultValue: PropTypes.number, toFixed: PropTypes.number, onChangeBack: PropTypes.func, disabled: PropTypes.bool, // colorStageGroup: PropTypes.array, isShading: PropTypes.bool, // colorGroup: PropTypes.array, } static defaultProps = { min: 0, // 最小值 max: 10, // 最大值 defaultValue: 0, // 设置初始取值 toFixed: 0, // 取小数点后几位 disabled: false, // 值为 true 时,滑块为禁用状态 onChangeBack() {}, // 会触发 onChange 事件,并把改变后的值作为参数传入 colorStageGroup: [4], // 颜色阶级显示分介数值 isShading: false, // 颜色是否缓动 colorGroup: ['#108ee9', '#108ee9'], // 颜色阶级显示分介颜色值(数量要比colorStageGroup多一个) } constructor(props) { super(props); this.state = { maxWidth: document.body.offsetWidth, everyWidth: 10, }; this.eventMoveStart = this.eventMoveStart.bind(this); this.eventMove = this.eventMove.bind(this); this.eventMoveEnd = this.eventMoveEnd.bind(this); } componentDidMount() { this.initDraw(this.props); } setBgColor(stage) { const { startR, startG, startB, stageR, stageG, stageB, } = this.state; const nowR = parseInt(startR + (stageR * stage), 10); const nowG = parseInt(startG + (stageG * stage), 10); const nowB = parseInt(startB + (stageB * stage), 10); return { r: nowR, g: nowG, b: nowB, }; } stepBgColor(step) { const { colorStageGroup } = this.props, len = colorStageGroup.length; for (let i = 0; i < len; i++) { if (len === 0) { if (colorStageGroup[i] >= step) { return 0; } return 1; } if (i === len - 1) { if (colorStageGroup[i] >= step) { return i; } return i + 1; } if (colorStageGroup[i] <= step && colorStageGroup[i + 1] > step) { return i; } } } eventMoveStart(e) { if (this.props.disabled) { return false; } // 阻止window窗体滚动 e.preventDefault && e.preventDefault(); e.stopPropagation && e.stopPropagation(); this.move(e); return true; } eventMoveEnd(e) { const { everyWidth } = this.state, { sliderBnt, lineLight } = this, valueWidth = this.value * everyWidth; sliderBnt.style.left = `${valueWidth}px`; lineLight.style.width = `${valueWidth}px`; } eventMove(e) { if (this.props.disabled) { return false; } // 阻止window窗体滚动 e.preventDefault && e.preventDefault(); e.stopPropagation && e.stopPropagation(); this.move(e); return true; } initDraw(props) { const { wrapLay, sliderBnt, lineLight } = this, { max, min, defaultValue, disabled, isShading, colorGroup, } = props, totle = max - min, everyWidth = Number(wrapLay.clientWidth) / totle, // 设置初始背景颜色 startBgColor = colorGroup[0], endBgColor = colorGroup[colorGroup.length - 1], reg = /^#([0-9a-fA-F]{6}|[0-9a-fA-F]{3})$/; if (!reg.test(startBgColor) || !reg.test(endBgColor)) { console.error('颜色格式错误'); return false; } // 设置 开始和结束的 r g b 颜色的值 let startR, startG, startB, endR, endG, endB; if (startBgColor.length === 4) { startR = parseInt(startBgColor.substring(1, 2) + startBgColor.substring(1, 2), 16); startG = parseInt(startBgColor.substring(2, 3) + startBgColor.substring(2, 3), 16); startB = parseInt(startBgColor.substring(3, 4) + startBgColor.substring(3, 4), 16); } else { startR = parseInt(startBgColor.substring(1, 3), 16); startG = parseInt(startBgColor.substring(3, 5), 16); startB = parseInt(startBgColor.substring(5, 7), 16); } if (endBgColor.length === 4) { endR = parseInt(endBgColor.substring(1, 2) + endBgColor.substring(1, 2), 16); endG = parseInt(endBgColor.substring(2, 3) + endBgColor.substring(2, 3), 16); endB = parseInt(endBgColor.substring(3, 4) + endBgColor.substring(3, 4), 16); } else { endR = parseInt(endBgColor.substring(1, 3), 16); endG = parseInt(endBgColor.substring(3, 5), 16); endB = parseInt(endBgColor.substring(5, 7), 16); } const stageR = endR - startR, stageG = endG - startG, stageB = endB - startB; this.setState({ maxWidth: wrapLay.clientWidth, everyWidth, offsetLeft: wrapLay.offsetLeft, startR, startG, startB, // endR, // endG, // endB, stageR, stageG, stageB, }); // 设置初始位置 sliderBnt.style.left = `${(defaultValue - min) * everyWidth}px`; lineLight.style.width = `${(defaultValue - min) * everyWidth}px`; // 设置初始颜色 if (!disabled && isShading) { const nowR = parseInt(startR + ((stageR * defaultValue) / totle), 10), nowG = parseInt(startG + ((stageG * defaultValue) / totle), 10), nowB = parseInt(startB + ((stageB * defaultValue) / totle), 10); lineLight.style.backgroundColor = `rgb(${nowR}, ${nowG}, ${nowB})`; } // 设置阶段颜色值 if (!disabled && !isShading) { lineLight.style.backgroundColor = colorGroup[this.stepBgColor(defaultValue)]; } } move(e) { const { isShading, colorGroup, min, onChangeBack, toFixed, } = this.props, { sliderBnt, lineLight } = this, { everyWidth, offsetLeft } = this.state; let pageX = e.touches[0].pageX - offsetLeft; pageX = pageX < 0 ? 0 : pageX; pageX = pageX > this.state.maxWidth ? this.state.maxWidth : pageX; let onvalue; if (toFixed <= 0) { onvalue = pageX < 50 ? Math.floor(pageX / everyWidth) + min : Math.ceil(pageX / everyWidth) + min; } else { onvalue = ((pageX / everyWidth) + min).toFixed(toFixed); } // const onvalue = pageX < 50 ? Math.floor(pageX / everyWidth) + min : // Math.ceil(pageX / everyWidth) + min; // const onvalue = pageX < 50 ? (pageX / everyWidth) + min : // (pageX / everyWidth) + min; sliderBnt.style.left = `${pageX}px`; lineLight.style.width = `${pageX}px`; this.value = onvalue; if (onChangeBack) { onChangeBack({ value: onvalue, }); } if (isShading) { const newColor = this.setBgColor(pageX / this.state.maxWidth); lineLight.style.backgroundColor = `rgb(${newColor.r}, ${newColor.g}, ${newColor.b})`; } // 设置阶段颜色值 if (!isShading) { lineLight.style.backgroundColor = colorGroup[this.stepBgColor(onvalue)]; } } render() { const { disabled, className } = this.props, cls = classNames({ 'jimu-slider': true, 'jimu-disabled': disabled, [className]: className, }); return ( <div className={cls} ref={(u) => { this.wrapLay = u; }}> {this.props.children && ( <div className="brd"> {this.props.children} </div> )} <div className="line-layout" onTouchMove={this.eventMove} onTouchStart={this.eventMoveStart} onTouchEnd={this.eventMoveEnd}> <div className="line-bg" /> <div className="line-light" ref={(u) => { this.lineLight = u; }} /> <div className="slider-bnt" ref={(u) => { this.sliderBnt = u; }} /> </div> </div> ); } } export default Slider;