172 lines
4.0 KiB
JavaScript
172 lines
4.0 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: null,
|
|
min: null,
|
|
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 {
|
|
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;
|
|
}
|
|
`
|
|
|
|
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
|
|
const { value: preValue, step, max, min } = this
|
|
const onMousemove = bind(document, 'mousemove', e => {
|
|
const distance = e.clientX - start
|
|
const diff = Math.round((distance / this.$runway.clientWidth) * 100)
|
|
let newValue = preValue + diff
|
|
newValue = Math.floor(newValue)
|
|
if (newValue < 0) {
|
|
newValue = 0
|
|
}
|
|
if (newValue > 100) {
|
|
newValue = 100
|
|
}
|
|
if (newValue % step) {
|
|
return
|
|
}
|
|
this.$bar.style.width = newValue + '%'
|
|
this.$dotWrap.style.left = newValue + '%'
|
|
this.$tips.style.left = newValue + '%'
|
|
|
|
this.value = newValue
|
|
})
|
|
|
|
const onMouseup = bind(document, 'mouseup', e => {
|
|
unbind(document, 'mousemove', onMousemove)
|
|
unbind(document, 'mouseup', onMouseup)
|
|
document.documentElement.classList.toggle('cursor-default')
|
|
})
|
|
}
|
|
onClick(e) {
|
|
if (e.target !== this.$refs.runway) {
|
|
return
|
|
}
|
|
const { clientWidth } = e.target
|
|
const { offsetX } = e
|
|
this.value = Math.floor((offsetX / clientWidth) * 100)
|
|
const barWidth = `${this.value}%`
|
|
|
|
this.$bar.style.width = barWidth
|
|
this.$dotWrap.style.left = barWidth
|
|
this.$tips.style.left = barWidth
|
|
}
|
|
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')
|
JavaScript
98.9%
CSS
1.1%