diff --git a/src/form/color.js b/src/form/color.js index 65be5b1..11fb05c 100644 --- a/src/form/color.js +++ b/src/form/color.js @@ -13,9 +13,14 @@ import { outsideClick, clearOutsideClick, nextTick, - offset + offset, + styleMap } from 'wkit' +const EV_OPTION = { once: true } +const DOC = document +const ROOT = document.documentElement + // H: 色相, S: 饱和度, B/V: 亮度 export function hsb2rgb(hsb) { var h = hsb.h @@ -133,29 +138,13 @@ class Color extends Component { value: { type: String, default: '', - attribute: false, observer(val) { - if (!this.panelShow) { + if (this.#show) { this.#calc(val) } } }, - disabled: false, - readonly: false - } - - // 临时的value, 组件内的操作, 修改的是这个值, 避免直接修改value触发太多的计算 - #value = '' - #x = 0 // 场景触点的X坐标 - #y = 0 // 场景触点的Y坐标 - #ht = 0 // 颜色池的触点坐标 - #at = 100 // 透明度条的触点坐标 - #sceneBg = '#ff0000' - #alphaBg = '#ff0000' - - cache = { - hsb: { h: 0, s: 100, b: 100 }, - rgba: { r: 255, g: 0, b: 0, a: 100 } + disabled: false } static styles = [ @@ -163,10 +152,10 @@ class Color extends Component { :host { display: inline-flex; } - .color-picker { + .container { position: relative; - width: 36px; - height: 36px; + width: 32px; + height: 32px; } .alpha-bg { background: linear-gradient( @@ -195,8 +184,8 @@ class Color extends Component { display: flex; width: 100%; height: 100%; - border: 2px solid var(--color-plain-2); - border-radius: 6px; + border: 1px solid var(--color-grey-2); + border-radius: 3px; cursor: pointer; transition: box-shadow 0.15s linear; @@ -204,7 +193,8 @@ class Color extends Component { width: 100%; height: 100%; border: 3px solid #fff; - border-radius: 6px; + border-radius: 3px; + background: var(--value); outline: none; } @@ -216,8 +206,9 @@ class Color extends Component { // .color-panel css` .color-panel { - display: none; + display: var(--show, none); position: absolute; + z-index: 1; left: 0; top: 38px; width: 310px; @@ -234,27 +225,14 @@ class Color extends Component { position: relative; width: 280px; height: 180px; - background: #f00; - - &::before, - &::after { - position: absolute; - left: 0; - top: 0; - width: 100%; - height: 100%; - content: ''; - } - - &::before { - background: linear-gradient(to right, #fff, transparent); - } - &::after { - background: linear-gradient(to bottom, transparent, #000); - } + background: linear-gradient(180deg, transparent, #000), + linear-gradient(90deg, #fff, transparent), var(--scene); .thumb { position: absolute; + z-index: 1; + left: var(--x); + top: var(--y); width: 0; height: 0; @@ -262,9 +240,9 @@ class Color extends Component { display: block; width: 10px; height: 10px; + border: 1px solid #fff; border-radius: 50%; background: rgba(32, 32, 32, 0.3); - box-shadow: 0 0 0 1px #fff; transform: translate(-5px, -5px); content: ''; } @@ -290,7 +268,7 @@ class Color extends Component { .thumb { position: absolute; left: 0; - top: 0; + top: var(--ht); width: 12px; height: 0; @@ -305,14 +283,6 @@ class Color extends Component { content: ''; } } - .hue { - position: relative; - display: block; - width: 12px; - height: 180px; - appearance: slider-vertical; - opacity: 0; - } } } .alpha-box { @@ -328,12 +298,12 @@ class Color extends Component { top: 0; width: 100%; height: 12px; - background: linear-gradient(to right, transparent, #f00); + background: linear-gradient(90deg, transparent, var(--alpha)); } .thumb { position: absolute; - left: 100%; + left: var(--at); top: 0; width: 0; height: 12px; @@ -415,9 +385,39 @@ class Color extends Component { } } } + `, + + css` + :host([disabled]) { + opacity: 0.6; + + .preview { + cursor: not-allowed; + + &:focus-within { + box-shadow: unset; + } + } + } ` ] + #show = false + + // 临时的value, 组件内的操作, 修改的是这个值, 避免直接修改value触发太多的计算 + #value = '' + #x = 0 // 场景触点的X坐标 + #y = 0 // 场景触点的Y坐标 + #ht = 0 // 颜色池的触点坐标 + #at = 100 // 透明度条的触点坐标 + #sceneBg = '#ff0000' + #alphaBg = '#ff0000' + + #cache = { + hsb: { h: 0, s: 100, b: 100 }, + rgba: { r: 255, g: 0, b: 0, a: 100 } + } + #calc(val) { var isHex var rgb @@ -431,53 +431,119 @@ class Color extends Component { isHex = /^#[0-9a-f]{3,6}$/.test(val) if (isHex) { - Object.assign(this.cache.rgba, hex2rgb(val), { a: 100 }) + Object.assign(this.#cache.rgba, hex2rgb(val), { a: 100 }) } else { var res = val.match(/rgba?\((\d+),\s*?(\d+),\s*?(\d+)[,\s]*?([\d\.]+)?\)/) if (res) { - this.cache.rgba = { r: +res[1], g: +res[2], b: +res[3], a: 100 } + this.#cache.rgba = { r: +res[1], g: +res[2], b: +res[3], a: 100 } if (res[4] !== undefined) { - this.cache.rgba.a = ~~(res[4] * 100) + this.#cache.rgba.a = ~~(res[4] * 100) } } else { return } } - this.cache.hsb = rgb2hsb(this.cache.rgba) + this.#cache.hsb = rgb2hsb(this.#cache.rgba) } toggleColorPanel() { - this.$refs.panel.style.display = 'block' - this.panelShow = true + if (this.disabled) { + return + } + this.#show = true this.#updateView() } // 透明度变化 - alphaChange(ev) { - var a = ev.target.value - var { r, g, b } = this.cache.rgba + #changeAlpha(ev) { + let a = +ev.target.value + let { r, g, b } = this.#cache.rgba - this.cache.rgba.a = a + this.#cache.rgba.a = a this.#updateView() } // 色彩池变化 - hueChange(ev) { - var h = 360 - ev.target.value - var { s, b } = this.cache.hsb - var rgba = this.cache.rgba - var hsb = { h, s, b } + #changeHue(h) { + h = h < 0 ? 0 : h > 360 ? 360 : h + let { s, b } = this.#cache.hsb + let rgba = this.#cache.rgba + let hsb = { h, s, b } Object.assign(rgba, hsb2rgb(hsb)) - this.cache.hsb = hsb - this.cache.rgba = rgba + this.#cache.hsb = hsb + this.#cache.rgba = rgba this.#updateView() } + // + #changeColor(x, y) { + let { hsb, rgba } = this.#cache + hsb.s = ~~((100 * x) / 280) + hsb.b = ~~((100 * (180 - y)) / 180) + Object.assign(rgba, hsb2rgb(hsb)) + + this.#cache.hsb = hsb + this.#cache.rgba = rgba + this.#updateView() + } + + #sceneMousedown(ev) { + let { x, y } = ev + let { left, top } = offset(ev.currentTarget) + let { scrollLeft, scrollTop } = ROOT + let _x = left - scrollLeft + let _y = top - scrollTop + + this.#changeColor(x - _x, y - _y) + + let callback = bind(DOC, 'mousemove', ({ x, y }) => { + x -= _x + y -= _y + + x = x < 0 ? 0 : x > 280 ? 280 : x + y = y < 0 ? 0 : y > 180 ? 180 : y + + this.#changeColor(x, y) + }) + bind(DOC, 'mouseup', _ => unbind(DOC, 'mousemove', callback), EV_OPTION) + } + + #poolMousedown(ev) { + let { y } = ev + let { top } = offset(ev.currentTarget) + let { scrollTop } = ROOT + let { clientHeight: h } = ev.currentTarget + let _y = top - scrollTop + + y -= _y + + this.#changeHue(~~((y / h) * 360)) + + let callback = bind(DOC, 'mousemove', ({ y }) => { + y -= _y + this.#changeHue(~~((y / h) * 360)) + }) + bind(DOC, 'mouseup', _ => unbind(DOC, 'mousemove', callback), EV_OPTION) + } + + #close(clear) { + if (this.#show) { + this.#show = false + this.#calc(this.value) + this.#updateView() + } + } + + #submit() { + this.value = this.#value + this.#close() + this.$emit('change', { data: this.#value }) + } #updateView() { - var { hsb, rgba } = this.cache + var { hsb, rgba } = this.#cache var sceneBg, color, alphaBg var x, y @@ -503,135 +569,68 @@ class Color extends Component { this.$requestUpdate() } - #changeColor(x, y) { - let { hsb, rgba } = this.cache - hsb.s = ~~((100 * x) / 280) - hsb.b = ~~((100 * (180 - y)) / 180) - Object.assign(rgba, hsb2rgb(hsb)) - - this.cache.hsb = hsb - this.cache.rgba = rgba - this.#updateView() - } - - closePanel() { - if (this.hasOwnProperty('panelShow')) { - this.$refs.panel.style.display = '' - this.#calc(this.value) - this.#updateView() - delete this.panelShow - } - } - - submit() { - this.$refs.panel.style.display = '' - this.value = this.#value - this.$emit('change', { data: this.#value }) - delete this.panelShow - } - mounted() { - var handleMove - // 更新一次视图 - nextTick(_ => this.#updateView()) - - bind(this.$refs.scene, 'mousedown', ev => { - ev.preventDefault() - - var { pageX, pageY } = ev - var { left, top } = offset(this.$refs.scene) - - var x = pageX - left - var y = pageY - top - - this.#changeColor(x, y) - - handleMove = bind(document, 'mousemove', ev => { - ev.preventDefault() - - var { pageX, pageY } = ev - - var x = pageX - left - var y = pageY - top - var rgb - - x = x < 0 ? 0 : x > 280 ? 280 : x - y = y < 0 ? 0 : y > 180 ? 180 : y - - this.#changeColor(x, y) - }) - }) - - this.handleUp = bind(document, 'mouseup', ev => { - ev.preventDefault() - unbind(document, 'mousemove', handleMove) - }) + this.#updateView() // 点击外部区别时,还原之前的颜色值 - this._outsideFn = outsideClick(this.$refs.panel, ev => { - this.closePanel() + this._outsideFn = outsideClick(this, ev => { + this.#close() }) } unmounted() { clearOutsideClick(this._outsideFn) - unbind(document, 'mouseup', this.handleUp) } render() { + let styles = styleMap({ + '--show': this.#show ? 'block' : 'none', + '--value': this.#value, + '--scene': this.#sceneBg, + '--x': this.#x + 'px', + '--y': this.#y + 'px', + '--ht': this.#ht + 'px', + '--at': this.#at + '%', + '--alpha': this.#alphaBg + }) + return html` -
+
- +
-
+ +
-
- +
+
-
- - +
+
+
-
- +
+
+
- - 清除 - 确定 + + this.#close(true)}>清除 + 确定
-
+
` } } diff --git a/src/form/slider.js b/src/form/slider.js index 57fec4b..5ff0b56 100644 --- a/src/form/slider.js +++ b/src/form/slider.js @@ -42,14 +42,6 @@ class Slider extends Component { lazy: 'num!0' } - #len = 100 - #stops = 10 // 断点数, 最大只显示10个断点 - #point = 10 // 每个断点的百分比 - #value = 0 // 内部的值, 固定使用 0-100范围的值 - #decimal = 0 //小数位 - - #stamp = 0 - static styles = [ css` :host { @@ -208,6 +200,14 @@ class Slider extends Component { ` ] + #len = 100 + #stops = 10 // 断点数, 最大只显示10个断点 + #point = 10 // 每个断点的百分比 + #value = 0 // 内部的值, 固定使用 0-100范围的值 + #decimal = 0 //小数位 + + #stamp = 0 + #updateRange() { let { min, max, step } = this if (min >= max) {