kui-vue
Version:
A high quality UI Toolkit built on Vue.js 2.0
246 lines (232 loc) • 7.07 kB
JSX
import Thumb from './thumb'
import { times } from '../_tool/number'
export default {
props: {
value: [Array, Number, String],
min: { type: Number, default: 0 },
max: { type: Number, default: 100 },
disabled: Boolean,
step: {
type: Number,
default: 1,
validator: (val) => val !== 0
},
size: String,
range: Boolean,
vertical: Boolean,
reverse: Boolean,
marks: Object,
included: { type: Boolean, default: true },
tipFormatter: [Function, Object],
tooltipVisible: Boolean
},
watch: {
value() {
this.defaultValue = this.getValue()
}
},
provide() {
return {
bar: this,
}
},
data() {
return {
defaultValue: this.getValue(),
// percent1: 0,
// percent2: 0,
// width: 0,
// left: 0,
isMouseDown: false
}
},
methods: {
getMinStep(percent) {
let { marks, step, min } = this
if (!marks) return times(Math.round((percent + min) / step), step)
let steps = Object.keys(marks)//, values = []
steps = steps.map(x => x - min)
if (step) {
steps.push(times(Math.round((percent) / step), step))
}
let result = steps.reduce((x, y) => Math.abs(x - percent) > Math.abs(y - percent) ? y : x)
// let result = steps.reduce((x, y) => Math.abs(x - percent) > Math.abs(y - percent) ? y : x)
// console.log(percent, result, steps)
return result + min
},
getValue() {
let { value = 0, range, min, max } = this, v;
let diff = max - min;
if (!range) {
v = value
if (value >= max) v = max
else if (value <= min) v = min
// let percent = (v - min) * 100 / diff
// v = this.getMinStep(percent)
} else {
if (!Array.isArray(value)) {
v = [0, 0]
} else {
v = [].concat(value)
}
let [x, y] = v
// let p1 = (x - min) * 100 / diff
// let p2 = (y - min) * 100 / diff
// x = this.getMinStep(p1)
// y = this.getMinStep(p2)
// console.log(p1 * 100, p2 * 100)
if (x >= max) x = max
else if (x <= min) x = min
if (y >= max) y = max
else if (y <= min) y = min
v = [x, y]
}
return v
},
click(e) {
let { disabled, range, vertical, step, max, min, defaultValue, reverse } = this
if (disabled) return;
let { width, height } = e.target.getBoundingClientRect()
let { layerX, layerY } = e
let percent = 0, diff = max - min;
if (reverse) {
percent = vertical ? (((height - layerY) / height) * diff) : (((width - layerX) / width) * diff);
} else {
percent = vertical ? ((layerY / height) * diff) : ((layerX / width) * diff);
}
let value = this.getMinStep(percent)
// let value = times(Math.round((percent + min) / step), step)
// console.log(value, step)
if (range) {
let [x, y] = defaultValue
let half = y > x ? (y - x) / 2 + x : (x - y) / 2 + y
value = value >= half && y > x ? [x, value] : [value, y]
}
this.defaultValue = value
this.$emit('input', value)
this.$emit('change', value)
},
isActice(a) {
let { defaultValue, reverse, max, min, vertical } = this
let active;
if (this.range) {
let [x, y] = defaultValue
active = x < y ? (a >= x && a <= y) : (a <= x && a >= y)
// console.log(a, active, `${a} >= ${x} && ${a} <= ${y}`)
} else {
active = a <= defaultValue
}
let diff = max - min
let pos = ((a - min) / diff) * 100 + '%'
let sty = {}
if (reverse) {
sty = vertical ?
{ bottom: pos, transform: 'translateY(50%)' } :
{ right: pos, transform: 'translateX(50%)' }
} else {
sty = vertical ?
{ top: pos } :
{ left: pos }
}
return { active, sty }
},
renderMark() {
let { marks } = this
if (!marks) return null
let mks = Object.keys(marks || {})
let txt = Object.values(marks || {})
return <div div class="k-slider-marks" >
{
mks.map(v => {
const { active, sty } = this.isActice(v);
return <div class={['k-slider-mark-symbol', { 'k-slider-mark-symbol-active': active }]} style={sty} />
})
}
{
mks.map((v, i) => {
let { active, sty } = this.isActice(v);
return <div class={['k-slider-mark-text', { 'k-slider-mark-text-active': active }]} style={sty}>{txt[i]}</div>
})
}
</div>
},
renderTrack() {
let { vertical, max, min, defaultValue, range, included, marks, reverse } = this
let percent1 = 0, percent2 = 0, diff = max - min;
let w, l;
if (!range) {
percent2 = ((defaultValue - min) / diff) * 100
} else {
let [x, y] = defaultValue
percent1 = ((x - min) / diff) * 100
percent2 = ((y - min) / diff) * 100
}
let trackSty = {}
// console.log(percent1, percent2)
if (percent2 > percent1) {
w = percent2 - percent1
l = percent1
} else {
w = percent1 - percent2
l = percent2
}
if (reverse) {
trackSty = vertical ? {
height: `${w}%`,
top: 'auto',
bottom: `${l}%`
} : {
width: `${w}%`,
left: 'auto',
right: `${l}%`
}
} else {
trackSty = vertical ? {
height: `${w}%`,
top: `${l}%`
} : {
width: `${w}%`,
left: `${l}%`
}
}
return (included && marks) || !marks ?
<div class="k-slider-track" style={{ ...trackSty }}></div> : null
},
thumbProps() {
let { vertical, disabled, range, step, reverse, max, min, defaultValue, tooltipVisible, tipFormatter, size } = this
return {
props: {
vertical, disabled, range, step, reverse, min, size,
max, tipFormatter, tooltipVisible,
value: range ? [].concat(defaultValue) : defaultValue * 1
},
on: {
input: (value) => {
if (value !== defaultValue) {
this.defaultValue = value
this.$emit('input', value)
this.$emit('change', value)
}
}
}
}
}
},
render() {
let { disabled, vertical, range } = this
let leftProps = this.thumbProps()
let rightProps = this.thumbProps()
let trackNode = this.renderTrack()
let markNode = this.renderMark()
return <div class={['k-slider', { 'k-slider-disabled': disabled, 'k-slider-vertical': vertical }]}>
<div class="k-slider-bar">
<div class="k-slider-rail" ref="rail" onClick={this.click}></div>
{trackNode}
{range ? <Thumb {...leftProps} /> : null}
<Thumb {...rightProps} type="right" />
{markNode}
</div>
{/* {this.renderMark()} */}
</div>
}
}