ui/src/slider/index.js

202 lines
4.7 KiB
JavaScript

/**
* {}
* @author yutent<yutent.io@gmail.com>
* @date 2023/03/21 16:14:10
*/
import { nextTick, css, bind, unbind, html, Component } from '@bd/core'
class Slider extends Component {
static props = {
value: {
type: Number,
default: 0,
observer() {}
},
max: 100,
min: 0,
step: 1,
disabled: false,
readonly: false,
vertical: false,
'show-tooltip': true
}
static styles = css`
:host {
display: block;
width: 100%;
height: 38px;
}
.slider {
position: relative;
display: flex;
align-items: center;
height: 100%;
}
.runway {
flex: 1;
position: relative;
height: 6px;
background: #e4e7ed;
border-radius: 99rem;
cursor: pointer;
.bar {
flex: 1;
pointer-events: none;
position: absolute;
height: 100%;
width: 0%;
border-radius: 99rem;
background: #409eff;
}
}
.dot-wrapper {
position: absolute;
display: flex;
justify-content: center;
align-items: center;
height: 36px;
width: 36px;
top: 50%;
left: 0%;
cursor: grab;
transform: translate(-50%, -50%);
.dot {
height: 20px;
width: 20px;
border-radius: 50%;
border: 2px solid #409eff;
background: #fff;
transition: transform 0.2s ease-in-out;
&:hover {
transform: scale(1.2);
}
}
}
.tips {
user-select: none;
position: absolute;
top: -100%;
border-radius: 4px;
padding: 10px;
z-index: 2000;
font-size: 12px;
line-height: 1.2;
min-width: 10px;
word-wrap: break-word;
color: #fff;
background: #303133;
transform: translateX(-50%);
&:after {
position: absolute;
border: 6px solid transparent;
bottom: -12px;
left: 50%;
transform: translateX(-50%);
content: '';
border-top-color: #303133;
}
}
.cursor-default {
cursor: grabbing !important;
}
`
progress = 0
mounted() {
console.log('slider mounted')
console.log(this.$refs, 'refs')
this.$bar = this.$refs.bar
this.$dotWrap = this.$refs.dotWrap
this.$runway = this.$refs.runway
this.$tips = this.$refs.tips
}
onMousedown(e) {
document.documentElement.classList.toggle('cursor-default')
const start = e.clientX
let { value: preValue, step, max, min, progress } = this
preValue = preValue || min
const onMousemove = bind(document, 'mousemove', e => {
const distance = e.clientX - start
const scale = distance / this.$runway.clientWidth
const diff = Math.round(scale * (max - min))
let newValue = Math.floor(preValue + diff)
// console.log({ diff, preValue })
let newProgress = progress + Math.floor(scale * 100)
if (newValue < min) {
newValue = min
}
if (newValue > max) {
newValue = max
}
if (newValue % step) {
return
}
// console.warn(newValue)
this.value = newValue
this.setProgress(newProgress)
})
const onMouseup = bind(document, 'mouseup', () => {
unbind(document, 'mousemove', onMousemove)
unbind(document, 'mouseup', onMouseup)
})
}
onClick(e) {
if (e.target !== this.$refs.runway) {
return
}
const { max, min, step } = this
const { clientWidth } = e.target
const { offsetX } = e
const range = max - min
const scale = offsetX / clientWidth
// console.log(
// {
// scale,
// range
// },
// scale * range + min
// )
let newValue = Math.floor(scale * range + min)
const mod = newValue % step
if (mod) {
const half = step / 2
if (mod > half) {
newValue += step - mod
} else {
newValue -= mod
}
}
this.value = newValue
console.log(scale * 100)
//const progress = Math.floor(scale * 100)
const progress = Math.floor(((newValue - min) / range) * 100)
// console.log({ progress })
this.setProgress(progress)
}
setProgress(val) {
val = Math.floor(val)
val = val > 100 ? 100 : val
val = val < 0 ? 0 : val
this.$bar.style.width = `${val}%`
this.$dotWrap.style.left = `${val}%`
this.$tips.style.left = `${val}%`
this.progress = val
}
render() {
return html`<div class="slider" ref="slider">
<div ref="runway" class="runway" @click=${this.onClick}>
<div class="bar" ref="bar"></div>
<div class="dot-wrapper" ref="dotWrap" @mousedown=${this.onMousedown}>
<div class="dot"></div>
</div>
</div>
<div class="tips" ref="tips">${this.value}</div>
</div>`
}
}
Slider.reg('slider')
百搭WCUI组件库, 基于web components开发。面向下一代的UI组件库
JavaScript 98.9%
CSS 1.1%