From 3b09af7968b88eec02fa47e38b179afd98b8a9d0 Mon Sep 17 00:00:00 2001 From: chenjiajian <770230504@qq.com> Date: Fri, 24 Mar 2023 14:46:59 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=8C=E6=88=90slider=E7=BB=84=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/slider/index.js | 350 +++++++++++++++++++++++++++++--------------- 1 file changed, 232 insertions(+), 118 deletions(-) diff --git a/src/slider/index.js b/src/slider/index.js index 085c7ac..3e70cf4 100644 --- a/src/slider/index.js +++ b/src/slider/index.js @@ -4,161 +4,246 @@ * @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 { static props = { value: { type: Number, default: 0, - observer() {} + observer(val) { + this.$bar && this.initValue(val) + } }, + type: 'info', max: 100, min: 0, step: 1, disabled: false, readonly: false, - vertical: false, - 'show-tooltip': true + vertical: false } - 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; + static styles = [ + css` + :host { + display: block; + width: 100%; + height: 38px; } - } - .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); + .slider { + position: relative; + display: flex; + align-items: center; + height: 100%; + } + .runway { + flex: 1; + position: relative; + height: 6px; + // width: 100%; + background: #e4e7ed; + border-radius: 99rem; + cursor: pointer; + .bar { + flex: 1; + pointer-events: none; + position: absolute; + height: 100%; + width: 0%; + border-radius: 99rem; + background: var(--color-blue-2, #409eff); } } - } - .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 { + .dot-wrapper { position: absolute; - border: 6px solid transparent; - bottom: -12px; - left: 50%; - transform: translateX(-50%); - content: ''; - border-top-color: #303133; + 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 var(--color-blue-2, #409eff); + background: #fff; + transition: transform 0.2s ease-in-out; + &:hover { + transform: scale(1.2); + } + } } - } - .cursor-default { - cursor: grabbing !important; - } - ` + .tips { + opacity: 0; + pointer-events: none; + 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%); + transition: opacity 0.2s ease-in-out; + &.show { + opacity: 1; + } + &:after { + position: absolute; + border: 6px solid transparent; + bottom: -12px; + left: 50%; + transform: translateX(-50%); + content: ''; + border-top-color: #303133; + } + } + `, + //ηŠΆζ€ + 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 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 + this.initValue(this.value) } onMousedown(e) { - document.documentElement.classList.toggle('cursor-default') - const start = e.clientX - let { value: preValue, step, max, min, progress } = this + let { + value: preValue, + step, + max, + min, + progress, + vertical, + disabled, + readOnly + } = this + if (disabled || readOnly) { + return + } + this.$tips.classList.toggle('show') preValue = preValue || min + + const start = vertical ? e.clientY : e.clientX const onMousemove = bind(document, 'mousemove', e => { - const distance = e.clientX - start - const scale = distance / this.$runway.clientWidth + e.preventDefault() + 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)) - 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 - } + let newValue = Math.floor(preValue + diff) + newValue = Math.max(newValue, min) + newValue = Math.min(newValue, max) if (newValue % step) { return } - // console.warn(newValue) this.value = newValue - this.setProgress(newProgress) + requestAnimationFrame(() => { + this.setProgress(vertical ? 100 - newProgress : newProgress) + }) + this.$emit('input') }) const onMouseup = bind(document, 'mouseup', () => { unbind(document, 'mousemove', onMousemove) unbind(document, 'mouseup', onMouseup) + this.$tips.classList.toggle('show') + this.$emit('change') }) } onClick(e) { if (e.target !== this.$refs.runway) { return } - const { max, min, step } = this - const { clientWidth } = e.target - const { offsetX } = e + const { max, min, step, vertical, disabled, readOnly } = this + if (disabled || readOnly) { + return + } + const { clientWidth, clientHeight } = e.target + const { offsetX, offsetY } = e const range = max - min - const scale = offsetX / clientWidth - // console.log( - // { - // scale, - // range - // }, - // scale * range + min - // ) + const scale = + (vertical ? offsetY : offsetX) / (vertical ? clientHeight : clientWidth) + let newValue = Math.floor(scale * range + min) const mod = newValue % step if (mod) { @@ -169,21 +254,50 @@ class Slider extends Component { newValue -= mod } } - this.value = newValue - console.log(scale * 100) - //const progress = Math.floor(scale * 100) + this.value = vertical ? range - newValue : newValue 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) } setProgress(val) { + const { vertical } = this 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 + val = Math.min(val, 100) + 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.$dotWrap.style.left = `${val}%` + this.$tips.style.left = `${val}%` + this.progress = val + } } render() { return html`