Merge branch 'master' of github.com:9th-js/wcui
commit
ae48529d72
|
@ -4,25 +4,28 @@
|
||||||
* @date 2023/03/21 16:14:10
|
* @date 2023/03/21 16:14:10
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { nextTick, css, bind, unbind, html, Component } from '@bd/core'
|
import { css, bind, unbind, html, Component } from '@bd/core'
|
||||||
|
|
||||||
class Slider extends Component {
|
class Slider extends Component {
|
||||||
static props = {
|
static props = {
|
||||||
value: {
|
value: {
|
||||||
type: Number,
|
type: Number,
|
||||||
default: 0,
|
default: 0,
|
||||||
observer() {}
|
observer(val) {
|
||||||
|
this.$bar && this.initValue(val)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
type: 'info',
|
||||||
max: 100,
|
max: 100,
|
||||||
min: 0,
|
min: 0,
|
||||||
step: 1,
|
step: 1,
|
||||||
disabled: false,
|
disabled: false,
|
||||||
readonly: false,
|
readonly: false,
|
||||||
vertical: false,
|
vertical: false
|
||||||
'show-tooltip': true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static styles = css`
|
static styles = [
|
||||||
|
css`
|
||||||
:host {
|
:host {
|
||||||
display: block;
|
display: block;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
@ -38,6 +41,7 @@ class Slider extends Component {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
position: relative;
|
position: relative;
|
||||||
height: 6px;
|
height: 6px;
|
||||||
|
// width: 100%;
|
||||||
background: #e4e7ed;
|
background: #e4e7ed;
|
||||||
border-radius: 99rem;
|
border-radius: 99rem;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
@ -48,7 +52,7 @@ class Slider extends Component {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
width: 0%;
|
width: 0%;
|
||||||
border-radius: 99rem;
|
border-radius: 99rem;
|
||||||
background: #409eff;
|
background: var(--color-blue-2, #409eff);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.dot-wrapper {
|
.dot-wrapper {
|
||||||
|
@ -66,7 +70,7 @@ class Slider extends Component {
|
||||||
height: 20px;
|
height: 20px;
|
||||||
width: 20px;
|
width: 20px;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
border: 2px solid #409eff;
|
border: 2px solid var(--color-blue-2, #409eff);
|
||||||
background: #fff;
|
background: #fff;
|
||||||
transition: transform 0.2s ease-in-out;
|
transition: transform 0.2s ease-in-out;
|
||||||
&:hover {
|
&:hover {
|
||||||
|
@ -75,6 +79,8 @@ class Slider extends Component {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.tips {
|
.tips {
|
||||||
|
opacity: 0;
|
||||||
|
pointer-events: none;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: -100%;
|
top: -100%;
|
||||||
|
@ -88,6 +94,10 @@ class Slider extends Component {
|
||||||
color: #fff;
|
color: #fff;
|
||||||
background: #303133;
|
background: #303133;
|
||||||
transform: translateX(-50%);
|
transform: translateX(-50%);
|
||||||
|
transition: opacity 0.2s ease-in-out;
|
||||||
|
&.show {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
&:after {
|
&:after {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
border: 6px solid transparent;
|
border: 6px solid transparent;
|
||||||
|
@ -98,67 +108,142 @@ class Slider extends Component {
|
||||||
border-top-color: #303133;
|
border-top-color: #303133;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.cursor-default {
|
`,
|
||||||
cursor: grabbing !important;
|
//状态
|
||||||
|
css`
|
||||||
|
:host([vertical]) {
|
||||||
|
display: inline-block;
|
||||||
|
width: 38px;
|
||||||
|
height: 250px;
|
||||||
|
.slider {
|
||||||
|
justify-content: center;
|
||||||
|
.runway {
|
||||||
|
flex: 0 0 auto;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column-reverse;
|
||||||
|
width: 6px;
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
|
cursor: pointer;
|
||||||
|
.bar {
|
||||||
|
height: 0%;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
.dot-wrapper {
|
||||||
|
left: 50%;
|
||||||
|
top: 100%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.tips {
|
||||||
|
top: 100%;
|
||||||
|
left: 50%;
|
||||||
|
transform: translate(-50%, -180%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
:host([loading]),
|
||||||
|
:host([disabled]) {
|
||||||
|
pointer-events: none;
|
||||||
|
cursor: not-allowed;
|
||||||
|
opacity: 0.6;
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
//配色
|
||||||
|
css`
|
||||||
|
$colors: (
|
||||||
|
primary: 'teal',
|
||||||
|
info: 'blue',
|
||||||
|
success: 'green',
|
||||||
|
warning: 'orange',
|
||||||
|
danger: 'red',
|
||||||
|
secondary: 'dark',
|
||||||
|
help: 'grey'
|
||||||
|
);
|
||||||
|
|
||||||
|
@loop $t, $c in $colors {
|
||||||
|
:host([type='#{$t}']) {
|
||||||
|
.bar {
|
||||||
|
background-color: var(--color-#{$c}-2);
|
||||||
|
}
|
||||||
|
.dot {
|
||||||
|
border-color: var(--color-#{$c}-2);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
]
|
||||||
progress = 0
|
progress = 0
|
||||||
mounted() {
|
mounted() {
|
||||||
console.log('slider mounted')
|
|
||||||
console.log(this.$refs, 'refs')
|
|
||||||
|
|
||||||
this.$bar = this.$refs.bar
|
this.$bar = this.$refs.bar
|
||||||
this.$dotWrap = this.$refs.dotWrap
|
this.$dotWrap = this.$refs.dotWrap
|
||||||
this.$runway = this.$refs.runway
|
this.$runway = this.$refs.runway
|
||||||
this.$tips = this.$refs.tips
|
this.$tips = this.$refs.tips
|
||||||
|
this.initValue(this.value)
|
||||||
}
|
}
|
||||||
onMousedown(e) {
|
onMousedown(e) {
|
||||||
document.documentElement.classList.toggle('cursor-default')
|
let {
|
||||||
const start = e.clientX
|
value: preValue,
|
||||||
let { value: preValue, step, max, min, progress } = this
|
step,
|
||||||
|
max,
|
||||||
|
min,
|
||||||
|
progress,
|
||||||
|
vertical,
|
||||||
|
disabled,
|
||||||
|
readOnly
|
||||||
|
} = this
|
||||||
|
if (disabled || readOnly) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.$tips.classList.toggle('show')
|
||||||
preValue = preValue || min
|
preValue = preValue || min
|
||||||
|
|
||||||
|
const start = vertical ? e.clientY : e.clientX
|
||||||
const onMousemove = bind(document, 'mousemove', e => {
|
const onMousemove = bind(document, 'mousemove', e => {
|
||||||
const distance = e.clientX - start
|
e.preventDefault()
|
||||||
const scale = distance / this.$runway.clientWidth
|
const distance = (vertical ? e.clientY : e.clientX) - start
|
||||||
|
const scale =
|
||||||
|
(distance /
|
||||||
|
(vertical ? this.$runway.clientHeight : this.$runway.clientWidth)) *
|
||||||
|
(vertical ? -1 : 1)
|
||||||
|
|
||||||
const diff = Math.round(scale * (max - min))
|
const diff = Math.round(scale * (max - min))
|
||||||
let newValue = Math.floor(preValue + diff)
|
|
||||||
// console.log({ diff, preValue })
|
|
||||||
let newProgress = progress + Math.floor(scale * 100)
|
let newProgress = progress + Math.floor(scale * 100)
|
||||||
if (newValue < min) {
|
let newValue = Math.floor(preValue + diff)
|
||||||
newValue = min
|
newValue = Math.max(newValue, min)
|
||||||
}
|
newValue = Math.min(newValue, max)
|
||||||
if (newValue > max) {
|
|
||||||
newValue = max
|
|
||||||
}
|
|
||||||
if (newValue % step) {
|
if (newValue % step) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// console.warn(newValue)
|
|
||||||
this.value = newValue
|
this.value = newValue
|
||||||
this.setProgress(newProgress)
|
requestAnimationFrame(() => {
|
||||||
|
this.setProgress(vertical ? 100 - newProgress : newProgress)
|
||||||
|
})
|
||||||
|
this.$emit('input')
|
||||||
})
|
})
|
||||||
|
|
||||||
const onMouseup = bind(document, 'mouseup', () => {
|
const onMouseup = bind(document, 'mouseup', () => {
|
||||||
unbind(document, 'mousemove', onMousemove)
|
unbind(document, 'mousemove', onMousemove)
|
||||||
unbind(document, 'mouseup', onMouseup)
|
unbind(document, 'mouseup', onMouseup)
|
||||||
|
this.$tips.classList.toggle('show')
|
||||||
|
this.$emit('change')
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
onClick(e) {
|
onClick(e) {
|
||||||
if (e.target !== this.$refs.runway) {
|
if (e.target !== this.$refs.runway) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
const { max, min, step } = this
|
const { max, min, step, vertical, disabled, readOnly } = this
|
||||||
const { clientWidth } = e.target
|
if (disabled || readOnly) {
|
||||||
const { offsetX } = e
|
return
|
||||||
|
}
|
||||||
|
const { clientWidth, clientHeight } = e.target
|
||||||
|
const { offsetX, offsetY } = e
|
||||||
const range = max - min
|
const range = max - min
|
||||||
const scale = offsetX / clientWidth
|
const scale =
|
||||||
// console.log(
|
(vertical ? offsetY : offsetX) / (vertical ? clientHeight : clientWidth)
|
||||||
// {
|
|
||||||
// scale,
|
|
||||||
// range
|
|
||||||
// },
|
|
||||||
// scale * range + min
|
|
||||||
// )
|
|
||||||
let newValue = Math.floor(scale * range + min)
|
let newValue = Math.floor(scale * range + min)
|
||||||
const mod = newValue % step
|
const mod = newValue % step
|
||||||
if (mod) {
|
if (mod) {
|
||||||
|
@ -169,22 +254,51 @@ class Slider extends Component {
|
||||||
newValue -= mod
|
newValue -= mod
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.value = newValue
|
this.value = vertical ? range - newValue : newValue
|
||||||
console.log(scale * 100)
|
|
||||||
//const progress = Math.floor(scale * 100)
|
|
||||||
const progress = Math.floor(((newValue - min) / range) * 100)
|
const progress = Math.floor(((newValue - min) / range) * 100)
|
||||||
// console.log({ progress })
|
this.setProgress(progress)
|
||||||
|
this.$emit('change')
|
||||||
|
if (!this.timeout) {
|
||||||
|
this.$tips.classList.toggle('show')
|
||||||
|
} else {
|
||||||
|
clearTimeout(this.timeout)
|
||||||
|
this.timeout = null
|
||||||
|
}
|
||||||
|
this.timeout = setTimeout(() => {
|
||||||
|
this.$tips.classList.toggle('show')
|
||||||
|
this.timeout = null
|
||||||
|
}, 1000)
|
||||||
|
}
|
||||||
|
initValue(val) {
|
||||||
|
const { max, min, vertical, disabled, readOnly } = this
|
||||||
|
if (disabled || readOnly) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const range = max - min
|
||||||
|
val = Math.max(val, min)
|
||||||
|
val = Math.min(val, max)
|
||||||
|
this.value = val
|
||||||
|
let progress = Math.floor(((val - min) / range) * 100)
|
||||||
|
progress = vertical ? 100 - progress : progress
|
||||||
this.setProgress(progress)
|
this.setProgress(progress)
|
||||||
}
|
}
|
||||||
setProgress(val) {
|
setProgress(val) {
|
||||||
|
const { vertical } = this
|
||||||
val = Math.floor(val)
|
val = Math.floor(val)
|
||||||
val = val > 100 ? 100 : val
|
val = Math.min(val, 100)
|
||||||
val = val < 0 ? 0 : val
|
val = Math.max(val, 0)
|
||||||
|
if (vertical) {
|
||||||
|
this.$bar.style.height = `${100 - val}%`
|
||||||
|
this.$dotWrap.style.top = `${val}%`
|
||||||
|
this.$tips.style.top = `${val}%`
|
||||||
|
this.progress = 100 - val
|
||||||
|
} else {
|
||||||
this.$bar.style.width = `${val}%`
|
this.$bar.style.width = `${val}%`
|
||||||
this.$dotWrap.style.left = `${val}%`
|
this.$dotWrap.style.left = `${val}%`
|
||||||
this.$tips.style.left = `${val}%`
|
this.$tips.style.left = `${val}%`
|
||||||
this.progress = val
|
this.progress = val
|
||||||
}
|
}
|
||||||
|
}
|
||||||
render() {
|
render() {
|
||||||
return html`<div class="slider" ref="slider">
|
return html`<div class="slider" ref="slider">
|
||||||
<div ref="runway" class="runway" @click=${this.onClick}>
|
<div ref="runway" class="runway" @click=${this.onClick}>
|
||||||
|
|
Loading…
Reference in New Issue