UNPKG

@minix-iot/ui

Version:

基于Vue的移动端轻量级UI组件库

283 lines (263 loc) 6.19 kB
import { Touch } from '../../utils/touch' import { DOMExtension } from '../../utils/extensions/dom' import { MathExtension } from '../../utils/extensions/math' import { Namespace } from "../../utils/namespace" const namespace = Namespace.Create("slider") export default { name: namespace.name, props: { linear: { type: Array, default: () => [] }, value: { type: Number, default: 0 }, min: { type: Number, default: 0 }, max: { type: Number, default: 100 }, step: { type: Number, default: 1 }, trackHeight: { type: Number, default: -1 }, buttonSize: { type: Number, default: -1 }, trackColor: { type: String }, barColor: { type: String }, scaleColor: { type: String }, buttonColor: { type: String }, theme: { type: String, default: 'brand' }, readonly: { type: Boolean, default: false }, disabled: { type: Boolean, default: false } }, model: { prop: 'value', event: 'input' }, data () { return { touch: Touch.Create(), current: 0, startValue: 0, dragStatus: '' } }, computed: { wrapperCls () { return namespace.derive('wrapper', { disabled: this.disabled }) }, cls () { return namespace.derive() }, trackCls () { return namespace.derive('track') }, barCls () { return namespace.derive('bar', [ this.theme ]) }, buttonCls () { return namespace.derive('button', [ this.theme ]) }, scaleCls () { return namespace.derive('scale-wrapper') }, scaleTextCls () { return namespace.derive('scale-text') }, sliderStyle () { const style = {} if (this.buttonSize > 0) { style.height = `${this.buttonSize}px` } return style }, trackStyle () { const style = {} if (this.trackColor) { style.background = this.trackColor } if (this.trackHeight) { style.height = `${this.trackHeight}px` } return style }, barStyle () { const style = { width: `${((this.value - this.min) * 100) / this.scope}%` } if (this.dragStatus) { style.transition = 'none' } if (this.linear.length > 0) { style.background = `linear-gradient(to right, ${this.linear.join(',')})` } if (this.barColor) { style.background = this.barColor } return style }, buttonStyle () { const style = {} if (this.linear.length > 0) { style.background = this.linear[this.linear.length - 1] } if (this.buttonColor) { style.background = this.buttonColor } if (this.buttonSize > 0) { style.width = `${this.buttonSize}px` style.height = `${this.buttonSize}px` style.borderRadius = `${this.buttonSize / 2} px` } return style }, scaleStyle () { const style = {} if (this.scaleColor) { style.color = this.scaleColor } return style }, canInteract () { return !this.disabled && !this.readonly }, scope () { return this.max - this.min } }, methods: { onClick (e) { e.stopPropagation() if (!this.canInteract) { return } const rect = this.$refs.slider.getBoundingClientRect() const delta = e.clientX - rect.left const total = rect.width const value = this.min + (delta / total) * this.scope this.update(value, true) }, onTouchStart (e) { if (!this.canInteract) { return } this.touch.start(e) this.current = this.value this.startValue = this.format(this.current) this.dragStatus = 'start' }, onTouchMove (e) { if (!this.canInteract) { return } if (this.dragStatus === 'start') { this.$emit('dragstart', e) } DOMExtension.PreventDefault(e) this.touch.move(e) this.dragStatus = 'draging' const rect = this.$refs.slider.getBoundingClientRect() const delta = this.touch.deltaX const total = rect.width const diff = (delta / total) * this.scope this.current = this.startValue + diff this.update(this.current) }, onTouchEnd (e) { if (!this.canInteract) { return } if (this.dragStatus === 'draging') { this.update(this.current, true) this.$emit('dragend', e) } this.dragStatus = '' }, format (value) { const min = +this.min const max = +this.max const step = + this.step const val = MathExtension.Clamp(value, min, max) const diff = Math.round((val - min) / step) * step return min + diff }, update (value, end = false) { const val = this.format(value) if (val !== this.value) { this.$emit('input', val) } if (end && val !== this.startValue) { this.$emit('change', val) } } }, render () { const renderSlider = () => ( <div ref={'slider'} class={this.cls} style={this.sliderStyle} onClick={this.onClick}> <div class={this.trackCls} style={this.trackStyle}> <div class={this.barCls} style={this.barStyle}> <div class={this.buttonCls} style={this.buttonStyle} onTouchstart={this.onTouchStart} onTouchmove={this.onTouchMove} onTouchend={this.onTouchEnd} onTouchcancel={this.onTouchEnd} onClick={e => e.stopPropagation()} > </div> </div> </div> </div> ) const renderScale = () => { if (this.$slots.default) { return ( <div class={this.scaleCls} style={this.scaleStyle}> {this.$slots.default} </div> ) } } return ( <div class={this.wrapperCls}> {renderSlider()} {renderScale()} </div> ) } }