/** * {数字文本框组件} * @author yutent * @date 2023/03/06 15:17:25 */ import { css, html, Component, nextTick } from '@bd/core' class WcNumber extends Component { static props = { type: 'primary', size: 'l', max: null, min: null, step: 1, value: { type: Number, default: 0, attribute: false }, readonly: false, autofocus: false, disabled: false, lazy: 1000 // 并发拦截时间, 单位毫秒 } static styles = [ // 基础样式 css` :host { overflow: hidden; display: inline-flex; min-width: 128px; height: 36px; user-select: none; -moz-user-select: none; color: var(--color-dark-1); border-radius: 3px; cursor: text; transition: box-shadow 0.15s linear; } :host(:focus-within) { box-shadow: 0 0 0 2px var(--color-plain-a); } .label { display: flex; width: 100%; height: 100%; margin: 0 auto; line-height: 1; font-size: 14px; border: 1px solid var(--color-grey-2); border-radius: inherit; background: var(--bg-color, #fff); color: inherit; cursor: text; span { display: flex; justify-content: center; align-items: center; width: 34px; height: 100%; font-size: 18px; cursor: pointer; &:first-child { border-radius: 3px 0 0 3px; border-right: 1px solid var(--color-grey-a); } &:last-child { border-radius: 0 3px 3px 0; border-left: 1px solid var(--color-grey-a); } &.disabled { cursor: not-allowed; opacity: 0.6; } } input { flex: 1; min-width: 32px; width: 0; height: 100%; padding: 0 6px; border: 0; border-radius: inherit; color: inherit; font: inherit; text-align: center; background: none; outline: none; box-shadow: none; cursor: inherit; &::placeholder { color: var(--color-grey-1); } } /* ----- */ } `, // 尺寸 css` @use 'sass:map'; $sizes: ( s: ( w: 52px, h: 20px, f: 12px ), m: ( w: 72px, h: 24px, f: 12px ), l: ( w: 108px, h: 32px, f: 14px ), xl: ( w: 132px, h: 36px, f: 14px ), xxl: ( w: 160px, h: 44px, f: 14px ), xxxl: ( w: 192px, h: 52px, f: 16px ), xxxxl: ( w: 212px, h: 64px, f: 18px ) ); @loop $s, $v in $sizes { :host([size='#{$s}']) { min-width: map.get($v, 'w'); height: map.get($v, 'h'); font-size: map.get($v, 'f'); .icon { --size: #{map.get($v, 'f')}; } } :host([size='#{$s}'][circle]) { width: map.get($v, 'h'); height: map.get($v, 'h'); } } :host([round]) { border-radius: 99rem; } `, // 配色 css` $colors: ( primary: 'teal', info: 'blue', success: 'green', warning: 'orange', danger: 'red', secondary: 'dark', help: 'grey' ); @loop $t, $c in $colors { :host([type='#{$t}']:focus-within) { box-shadow: 0 0 0 2px var(--color-#{$c}-a); } :host([type='#{$t}']) span { border-color: var(--color-#{$c}-a); } :host([type='#{$t}']) .label { border-color: var(--color-#{$c}-2); } } `, // 状态 css` :host([disabled]) { cursor: not-allowed; opacity: 0.6; } /* --- */ :host([readonly]) .label { cursor: default; opacity: 0.8; span { cursor: inherit; } } :host([disabled]) .label { background: var(--color-plain-1); cursor: not-allowed; opacity: 0.6; span { cursor: inherit; } } ` ] created() { this.stamp = 0 } mounted() { if (this.autofocus) { // 需要focus()才能聚焦成功 nextTick(_ => this.$refs.input.focus()) } this.value = this.clapm(this.value) this.$refs.input.value = this.value } onClick(e) { if (e.target.classList.contains('disabled')) { return } const { disabled, readOnly } = this if (disabled || readOnly) { return } const { act } = e.target.dataset this.updateValue(act) } updateValue(act) { const { max, min, step, value } = this if (act === '+') { if (max === null || value + step <= max) { this.value += step } else { this.value = max } } else { if (min === null || value - step >= min) { this.value -= step } else { this.value = min } } this.$emit('input') } onChange(e) { this.value = this.clapm(e.target.value) this.$refs.input.value = this.value } onKeydown(ev) { const now = Date.now() const { lazy, disabled, readOnly } = this if (disabled || readOnly) { return } // up: 38, down: 40 if (ev.keyCode === 38 || ev.keyCode === 40) { ev.preventDefault() return this.updateValue(ev.keyCode === 38 ? '+' : '-') } // 回车触发submit事件 if (ev.keyCode === 13) { ev.preventDefault() // 并发拦截 if (lazy && now - this.stamp < lazy) { return } this.stamp = now this.value = this.clapm(ev.target.value) this.$refs.input.value = this.value this.$emit('submit', { value: this.value }) } } clapm(val) { const max = this.max ?? Number.MAX_SAFE_INTEGER const min = this.min ?? Number.MIN_SAFE_INTEGER return Math.min(max, Math.max(+val, min)) } render() { return html`
- this.max ? 'disabled' : ''} @click=${this.onClick} >+
` } } WcNumber.reg('number')