diff --git a/src/components/slider/README.md b/src/components/slider/README.md index 93e314e..f8c3136 100644 --- a/src/components/slider/README.md +++ b/src/components/slider/README.md @@ -3,6 +3,7 @@ 工作职责: - 滑块空间 +- 滑块拖动后返回value值 ## 类型包括: @@ -11,28 +12,56 @@ ``` ``` - -2. 滑块中小球左侧进行填充 --- `filled` +2. `coverWidth` --- 初始填充 ``` - + + ``` -3. 禁用滑块 --- `disabled` +3. `disabled` --- 禁用滑块 ``` + ``` - -4. 分格滑块 --- `Tick` +4. `unfilled` --- 滑块中小球左侧不进行填充 ``` - - + + + ``` -5. 左侧图标|滑块|右侧图标 + +5. `Tick` --- 分格滑块(默认是unfilled属性) + min=0,mix=100,按照需求填写step(每一格)的大小
+ example :
+ step="25" 表示把slider分为4块
+ coverWidth="40%" 表示初始小球落在第二格上 + + + ``` - + + ``` +6. `vertical` --- 垂直slider + +``` + + + +``` +7. 左侧图标|滑块|右侧图标 + +``` + +

+
+``` + +## 后续需解决的问题: +- tick 属性中小球不能完全覆盖step +- vertical 属性变化太快 diff --git a/src/components/slider/slider-styles.ts b/src/components/slider/slider-styles.ts index 237be0a..ec59347 100644 --- a/src/components/slider/slider-styles.ts +++ b/src/components/slider/slider-styles.ts @@ -1,16 +1,38 @@ import {css, CSSResult} from 'lit' export const sharedStyles: CSSResult = css` :host { - --cover-width: 100px; - --dot-move: 87px; + --cover-width: 0px; + --dot-move: 0px; + --vWidth: 8px; } .content { - margin: 5px 5px; + height: 2px; + margin: 50px; position: relative; - padding: 50px 50px; - border: 1px solid skyblue; + padding: 8px; + /*border: 1px solid skyblue;*/ border-radius: 5px; } + .v-content { + width: 2px; + margin: 0px 2px; + position: relative; + padding: 200px 10px; + /*border: 1px solid skyblue;*/ + border-radius: 5px; + } + + .v-sliderBar { + position: absolute; + width: var(--vWidth); + height: 80%; + left: calc(50% - var(--vWidth) / 2); + top: 0px; + background: rgba(0, 0, 0, 0.08); + border-radius: 20px; + overflow: hidden; + } + .sliderBar { position: absolute; width: 100%; @@ -18,32 +40,93 @@ export const sharedStyles: CSSResult = css` left: 0px; right: 0px; top: calc(50% - 6px / 2); - background: rgba(0, 0, 0, 0.06); - border-radius: 5px; + background: rgba(0, 0, 0, 0.08); + border-radius: 8px; + } + .v-progress { + position: absolute; + width: var(--vWidth); + height: var(--cover-width); + left: 0px; + bottom: 0px; + border-radius: 0 0 20px 20px; + background: #404040; } .progress { position: absolute; width: var(--cover-width); - /*width: 100px;*/ height: 6px; left: 0px; right: 0px; top: calc(50% - 6px / 2); background: #4d4d4d; - border-radius: 5px; + border-radius: 5px 0 0 5px; } .dot { position: absolute; left: var(--dot-move); - width: 26px; - height: 26px; - top: calc(50% - 26px / 2); + width: 20px; + height: 20px; + top: calc(50% - 20px / 2); background: #544f4f; border-radius: 50%; + z-index: 1; } p { position: absolute; right: 5px; top: 1px; } + :host([disabled]) .progress { + background: #c0c0c0; + } + :host([disabled]) .v-progress { + background: #c0c0c0; + } + :host([disabled]) .step { + background: #c0c0c0; + } + :host([tick]) .step { + background: #c0c0c0; + } + :host([tick]) .sliderBar { + background: #c0c0c0; + border-radius: 0 0 0 0; + height: 4px; + } + :host([disabled]) .dot { + background: #c0c0c0; + } + :host([unfilled]) .progress { + background: none; + } + :host([tick]) .progress { + background: none; + } + .step { + position: absolute; + left: calc(var(--i) * 99.3%); + top: calc(50% - 10px / 2); + width: 3px; + height: 10px; + background-color: #d5d5d5; + border-radius: 3px; + } + ::slotted(span)::before { + font-size: 27px; + font-family: 'gaia-icons'; + content: attr(data-icon); + text-align: center; + position: relative; + top: 357px; + } + ::slotted(p)::before { + font-size: 27px; + font-family: 'gaia-icons'; + content: attr(data-icon); + text-align: center; + position: relative; + top: 74px; + left: 5px; + } ` diff --git a/src/components/slider/slider.ts b/src/components/slider/slider.ts index fa55319..5d6ae0c 100644 --- a/src/components/slider/slider.ts +++ b/src/components/slider/slider.ts @@ -1,9 +1,7 @@ -import {html, LitElement, CSSResultArray} from 'lit' +import {html, LitElement, CSSResultArray, PropertyValueMap} from 'lit' import {customElement, property, query} from 'lit/decorators.js' import {sharedStyles} from './slider-styles' -export const variants = ['filled', 'tick'] - @customElement('star-slider') export class StarSlider extends LitElement { _coverWidth: string = '' @@ -14,21 +12,28 @@ export class StarSlider extends LitElement { @query('.content') content!: HTMLDivElement @query('.sliderBar') sliderBar!: HTMLDivElement @query('.progress') progress!: HTMLDivElement + @query('.v-sliderBar') vSliderBar!: HTMLDivElement + @query('.v-progress') vProgress!: HTMLDivElement @query('.dot') dot!: HTMLDivElement @query('p') p!: HTMLParagraphElement + + @property({type: Boolean}) disabled = false + @property({type: Boolean}) tick = false + @property({type: Boolean}) vertical = false @property({type: Number}) startX = 0 + @property({type: Number}) startY = 0 @property({type: Number}) touchX = 0 + @property({type: Number}) touchY = 0 @property({type: Number}) moveX = 0 + @property({type: Number}) moveY = 0 @property({type: Number}) newX = 0 + @property({type: Number}) newY = 0 @property({type: Number}) barWidth = 0 @property({type: Number}) dotL = 0 @property({type: Number}) proportion = 0 - @property({type: String}) pValue = '' - @property({type: Number}) sliderBarLeft = 0 - @property({type: Number}) sliderBarRight = 0 - @property({type: Number}) ball = 0 - @property({type: String}) sliderCoverWidth = '' - @property({type: String}) ballMove = '' + @property({type: Number}) barX = 0 + @property({type: String}) endValue = '' + @property({type: String}) step = '' @property({type: String}) get coverWidth() { return this._coverWidth @@ -36,57 +41,202 @@ export class StarSlider extends LitElement { set coverWidth(value: string) { this.style.setProperty('--cover-width', value) this._coverWidth = value + this.style.setProperty('--dot-move', this._coverWidth) } render() { - return html` -
-

${this.pValue}

-
-
-
+ if (!this.vertical) { + return html` + +
+
+
+
+
-
- ` + ` + } else { + return html` + +
+
+
+
+
+ ` + } } + protected firstUpdated( + _changedProperties: PropertyValueMap | Map + ): void { + if (this.vertical) { + this.touchStart = this.touchStartVertical + this.touchEnd = this.touchEndVertical + this.touchMove = this.touchMoveVertical + } + if (this.tick) { + var tickStep = 100 / parseInt(this.step) + for (let i = 0; i <= tickStep; i++) { + const stepTick = document.createElement('div') + stepTick.style.setProperty('--i', String(i / tickStep)) + stepTick.classList.add('step') + this.sliderBar.appendChild(stepTick) + } + } + } + private touchStart(evt: TouchEvent) { - this.barWidth = this.sliderBar.offsetWidth - this.dot.offsetWidth //总长度减去小球覆盖的部分 - this.dotL = this.dot.offsetLeft //小球左侧相对于父元素的左边距 - this.startX = evt.touches[0].clientX //手指点下的 X 坐标 + if (!this.disabled) { + this.touchX = evt.touches[0].clientX //手指触摸的 x 坐标 + // 黑色覆盖部分 + this.barX = + this.touchX - + this.sliderBar.getBoundingClientRect().left - + this.dot.offsetWidth * 0.5 + this.barWidth = this.sliderBar.offsetWidth - this.dot.offsetWidth + if (this.barX < 0) { + this.barX = 0 + } + if (this.barX >= this.barWidth) { + this.barX = this.barWidth + } + this.proportion = (this.barX / this.barWidth) * 100 + this.endValue = Math.ceil(this.proportion) + '' + if (this.tick) { + // tick跳格滑动 + var tickStep = 100 / parseInt(this.step) //分为几格 + for (let i = 0; i <= tickStep; i++) { + if (this.barX > (this.barWidth * (i + 0.5)) / tickStep) { + this.style.setProperty( + '--dot-move', + (this.barWidth * (i + 1)) / tickStep + 'px' + ) + } + if (this.barX == 0) { + this.style.setProperty('--dot-move', 0 + 'px') + } + } + } else { + this.style.setProperty('--dot-move', this.barX + 'px') + this.progress.style.setProperty( + 'width', + (this.barWidth * Math.ceil(this.proportion)) / 100 + 'px' + ) + } + // 重新初始化防止滑块增量 + this.startX = evt.touches[0].clientX //手指点下的初始 X&Y 坐标 + this.barWidth = this.sliderBar.offsetWidth - this.dot.offsetWidth //总长度减去小球覆盖的部分 + this.dotL = this.dot.offsetLeft //小球左侧相对于父元素的左边距 + } } private touchMove(evt: TouchEvent) { - //阻止默认行为 - evt.preventDefault() - this.touchX = evt.touches[0].clientX //整个屏幕实时触摸的 X 坐标 - this.moveX = this.touchX - this.startX //手指移动的距离 - //判断最大值和最小值 - this.newX = this.dotL + this.moveX - if (this.newX < 0) { - this.newX = 0 + if (!this.disabled) { + //阻止默认行为 + evt.preventDefault() + this.touchX = evt.touches[0].clientX //整个屏幕实时触摸的 X 坐标 + this.moveX = this.touchX - this.startX //手指移动的距离 + + //判断最大值和最小值 + this.newX = this.dotL + this.moveX + + if (this.newX < 0) { + this.newX = 0 + } + if (this.newX >= this.barWidth) { + this.newX = this.barWidth + } + //计算比例 + this.proportion = (this.newX / this.barWidth) * 100 + //取整 + this.endValue = Math.ceil(this.proportion) + '' + if (!this.tick) { + this.style.setProperty('--dot-move', this.newX + 'px') + this.progress.style.setProperty( + 'width', + (this.barWidth * Math.ceil(this.proportion)) / 100 + 'px' + ) + } else { + // tick跳格滑动 + var tickStep = 100 / parseInt(this.step) //分为几格 + for (let i = 0; i <= tickStep; i++) { + if (this.newX > (this.barWidth * (i + 0.5)) / tickStep) { + this.style.setProperty( + '--dot-move', + (this.barWidth * (i + 1)) / tickStep + 'px' + ) + this.proportion = + ((this.barWidth * (i + 1)) / tickStep / this.barWidth) * 100 + //取整 + this.endValue = Math.ceil(this.proportion) + '' + } + if (this.newX == 0) { + this.style.setProperty('--dot-move', 0 + 'px') + this.endValue = 0 + '' + } + } + } } - if (this.newX >= this.barWidth) { - this.newX = this.barWidth - } - //改变dot的left值 - this.style.setProperty('--dot-move', this.newX + 'px') - //计算比例 - this.proportion = (this.newX / this.barWidth) * 100 - this.pValue = Math.ceil(this.proportion) + '' - this.progress.style.setProperty( - 'width', - (this.barWidth * Math.ceil(this.proportion)) / 100 + 'px' - ) } private touchEnd(evt: TouchEvent) { - return console.log(this.pValue) + if (this.tick) { + return console.log(10 * Math.round(parseInt(this.endValue) / 10) + '') + } else { + return console.log(this.endValue) + } + } + + private touchStartVertical(evt: TouchEvent) { + if (!this.disabled) { + this.startY = evt.touches[0].clientY //手指点下的初始 Y 坐标 + this.barWidth = this.vSliderBar.offsetHeight //总长度 + this.dotL = this.barWidth - this.vProgress.offsetTop //黑条长度 + //按压音量条变宽 + this.vSliderBar.style.setProperty('--vWidth', '16px') + this.vProgress.style.setProperty('--vWidth', '16px') + } + } + private touchMoveVertical(evt: TouchEvent) { + if (!this.disabled) { + //阻止默认行为 + evt.preventDefault() + this.touchY = evt.touches[0].clientY //整个屏幕实时触摸的 Y 坐标 + this.moveY = this.startY - this.touchY //手指移动的距离 + //判断最大值和最小值 + this.newY = this.dotL + this.moveY + if (this.newY < 0) { + // console.log('到底了') + this.newY = 0 + } + if (this.newY >= this.barWidth) { + // console.log('超了') + this.newY = this.barWidth + } + //计算比例 + this.proportion = (this.newY / this.barWidth) * 100 + //取整 + this.endValue = Math.ceil(this.proportion) + '' + this.vProgress.style.setProperty('height', this.newY + 'px') + } + } + private touchEndVertical(evt: TouchEvent) { + if (!this.disabled) { + this.vProgress.style.setProperty('--vWidth', '8px') + this.vSliderBar.style.setProperty('--vWidth', '8px') + return console.log(this.endValue) + } } } - declare global { interface HTMLElementTagNameMap { 'star-slider': StarSlider diff --git a/src/test/panels/slider/slider.ts b/src/test/panels/slider/slider.ts index fa301f0..8933900 100644 --- a/src/test/panels/slider/slider.ts +++ b/src/test/panels/slider/slider.ts @@ -1,29 +1,68 @@ import {html, LitElement, css} from 'lit' -import {customElement} from 'lit/decorators.js' +import {customElement, property} from 'lit/decorators.js' +import '../icon/icon' @customElement('panel-slider') export class PanelSlider extends LitElement { + @property({type: String}) icon = '' + static styles = css` div { position: relative; - border: 1px solid; margin: 50px 50px; border-radius: 5px; } + #a { + position: absolute; + left: 100px; + top: 45px; + } + #b { + position: absolute; + left: 200px; + top: 45px; + } ` render() { return html`
-

default

- -

初始化覆盖长度

- - +

vertical

+ + + + + + + + + +

default - 默认

+ +

+
+

coverWidth - 初始覆盖长度

+ +

+
+ +

+

disabled

- - - + + +

unfilled - 无覆盖

+ + +

tick

+
step="10"
+ +
step="20"
+ +
step="50"
+ +
step="25"
+
` }