重构number组件完成

master
yutent 2023-11-21 12:07:22 +08:00
parent bef7dac956
commit 88634682f7
2 changed files with 118 additions and 110 deletions

View File

@ -23,7 +23,7 @@ class Button extends Component {
} }
}, },
disabled: false, disabled: false,
lazy: 'num!0' // 并发拦截时间, 单位毫秒 lazy: 'num!1000' // 并发拦截时间, 单位毫秒
} }
static styles = [ static styles = [
@ -252,9 +252,10 @@ class Button extends Component {
] ]
#cacheIcon #cacheIcon
#stamp = 0
created() { created() {
this.stamp = 0 this.#stamp = 0
this._clickFn = this.$on( this._clickFn = this.$on(
'click', 'click',
@ -266,10 +267,10 @@ class Button extends Component {
return ev.stopPropagation() return ev.stopPropagation()
} }
// 并发拦截 // 并发拦截
if (lazy > 0 && now - this.stamp < lazy) { if (lazy > 0 && now - this.#stamp < lazy) {
return ev.stopPropagation() return ev.stopPropagation()
} }
this.stamp = now this.#stamp = now
}, },
true true
) )

View File

@ -4,77 +4,84 @@
* @date 2023/03/06 15:17:25 * @date 2023/03/06 15:17:25
*/ */
import { css, html, Component, nextTick } from 'wkit' import { css, html, Component } from 'wkit'
class WcNumber extends Component { const MAX_VALUE = 1e9 - 1
const MIN_VALUE = -MAX_VALUE
class InputNumber extends Component {
static props = { static props = {
type: 'primary', max: `num!${MAX_VALUE}`,
size: 'l', min: `num!${MIN_VALUE}`,
max: { type: Number, default: null }, step: 'num!1',
min: { type: Number, default: null },
step: 1,
value: { value: {
type: Number, type: Number,
default: 0, default: 0,
attribute: false observer(v) {
this.value = this.#fix(v)
}
}, },
readonly: false, readonly: false,
autofocus: false, autofocus: false,
disabled: false, disabled: false,
lazy: 1000 // 并发拦截时间, 单位毫秒 lazy: 'num!1000' // 并发拦截时间, 单位毫秒
} }
static styles = [ static styles = [
// 基础样式 // 基础样式
css` css`
:host { :host {
overflow: hidden;
display: inline-flex; display: inline-flex;
min-width: 128px; min-width: 128px;
height: 36px; height: 32px;
user-select: none;
-moz-user-select: none;
color: var(--color-dark-1); color: var(--color-dark-1);
border-radius: 3px; border-radius: 3px;
font-size: 14px;
cursor: text; cursor: text;
transition: box-shadow 0.15s linear; transition: box-shadow 0.15s linear;
-webkit-user-select: none;
user-select: none;
} }
:host(:focus-within) { :host(:focus-within) {
box-shadow: 0 0 0 2px var(--color-plain-a); box-shadow: 0 0 0 2px var(--color-plain-a);
} }
.label {
.container {
display: flex; display: flex;
width: 100%; width: 100%;
height: 100%; height: 100%;
margin: 0 auto; margin: 0 auto;
line-height: 1; line-height: 1;
font-size: 14px;
border: 1px solid var(--color-grey-2); border: 1px solid var(--color-grey-2);
border-radius: inherit; border-radius: inherit;
background: var(--bg-color, #fff); background: #fff;
color: inherit; color: inherit;
cursor: text; cursor: text;
span { button {
display: flex; display: flex;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
width: 34px; width: 34px;
height: 100%; height: 100%;
border: 0;
font-size: 18px; font-size: 18px;
font-family: Tahoma, Verdana, Helvetica, Arial, sans-serif;
background: var(--color-plain-1);
color: inherit;
cursor: pointer; cursor: pointer;
&:first-child { &:first-child {
border-radius: 3px 0 0 3px; border-radius: 2px 0 0 2px;
border-right: 1px solid var(--color-grey-a); border-right: 1px solid var(--color-grey-1);
} }
&:last-child { &:last-child {
border-radius: 0 3px 3px 0; border-radius: 0 2px 2px 0;
border-left: 1px solid var(--color-grey-a); border-left: 1px solid var(--color-grey-1);
} }
&.disabled { &[disabled] {
cursor: not-allowed; cursor: not-allowed;
opacity: 0.6; opacity: 0.6;
} }
@ -87,18 +94,12 @@ class WcNumber extends Component {
height: 100%; height: 100%;
padding: 0 6px; padding: 0 6px;
border: 0; border: 0;
border-radius: inherit;
color: inherit; color: inherit;
font: inherit; font-size: inherit;
text-align: center; text-align: center;
background: none; background: none;
outline: none; outline: none;
box-shadow: none;
cursor: inherit; cursor: inherit;
&::placeholder {
color: var(--color-grey-1);
}
} }
/* ----- */ /* ----- */
} }
@ -117,11 +118,6 @@ class WcNumber extends Component {
h: 24px, h: 24px,
f: 12px f: 12px
), ),
l: (
w: 108px,
h: 32px,
f: 14px
),
xl: ( xl: (
w: 132px, w: 132px,
h: 36px, h: 36px,
@ -130,7 +126,7 @@ class WcNumber extends Component {
xxl: ( xxl: (
w: 160px, w: 160px,
h: 44px, h: 44px,
f: 14px f: 16px
) )
); );
@ -140,18 +136,21 @@ class WcNumber extends Component {
height: map.get($v, 'h'); height: map.get($v, 'h');
font-size: map.get($v, 'f'); font-size: map.get($v, 'f');
.icon { button {
--wc-icon-size: #{map.get($v, 'f')}; width: map.get($v, 'h') + 2;
} }
} }
:host([size='#{$s}'][circle]) {
width: map.get($v, 'h');
height: map.get($v, 'h');
}
} }
:host([round]) { :host([round]) {
border-radius: 99rem; border-radius: 22px;
button:first-child {
border-radius: 22px 0 0 22px;
}
button:last-child {
border-radius: 0 22px 22px 0;
}
} }
`, `,
// 配色 // 配色
@ -173,7 +172,7 @@ class WcNumber extends Component {
:host([type='#{$t}']) span { :host([type='#{$t}']) span {
border-color: var(--color-#{$c}-a); border-color: var(--color-#{$c}-a);
} }
:host([type='#{$t}']) .label { :host([type='#{$t}']) .container {
border-color: var(--color-#{$c}-2); border-color: var(--color-#{$c}-2);
} }
} }
@ -185,14 +184,14 @@ class WcNumber extends Component {
opacity: 0.6; opacity: 0.6;
} }
/* --- */ /* --- */
:host([readonly]) .label { :host([readonly]) .container {
cursor: default; cursor: default;
opacity: 0.8; opacity: 0.8;
span { span {
cursor: inherit; cursor: inherit;
} }
} }
:host([disabled]) .label { :host([disabled]) .container {
background: var(--color-plain-1); background: var(--color-plain-1);
cursor: not-allowed; cursor: not-allowed;
opacity: 0.6; opacity: 0.6;
@ -203,54 +202,66 @@ class WcNumber extends Component {
` `
] ]
created() { #stamp = 0
this.stamp = 0
}
mounted() { mounted() {
if (this.autofocus) { if (this.autofocus) {
// 需要focus()才能聚焦成功 // 需要focus()才能聚焦成功
nextTick(_ => this.$refs.input.focus()) this.$refs.input.focus()
} }
this.value = this.clapm(this.value) this.value = this.#fix(this.$refs.input.value)
this.$refs.input.value = this.value this.$refs.input.value = this.value
} }
onClick(e) { #click(ev) {
if (e.target.classList.contains('disabled')) { let { disabled, readOnly } = this
return let { act } = ev.target.dataset
}
const { disabled, readOnly } = this
if (disabled || readOnly) { if (disabled || readOnly) {
return return
} }
const { act } = e.target.dataset
this.updateValue(act) this.#updateValue(act)
} }
updateValue(act) {
const { max, min, step, value } = this #fetch(value) {
if (act === '+') { this.value = value
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') this.$emit('input')
this.$emit('change')
} }
onChange(e) {
this.value = this.clapm(e.target.value) #updateValue(act) {
let { max, min, step, value } = this
if (act === '+') {
if (value >= max) {
return
}
value += step
} else {
if (value <= min) {
return
}
value -= step
}
this.#fetch(value)
this.$refs.input.value = this.value this.$refs.input.value = this.value
} }
onKeydown(ev) {
const now = Date.now() #changed(ev) {
const { lazy, disabled, readOnly } = this let _value = +ev.target.value
let value = this.#fix(_value)
if (value !== _value) {
ev.target.value = value
}
if (this.value !== value) {
this.#fetch(value)
}
}
#keydown(ev) {
let now = Date.now()
let { lazy, disabled, readOnly } = this
if (disabled || readOnly) { if (disabled || readOnly) {
return return
@ -259,62 +270,58 @@ class WcNumber extends Component {
// up: 38, down: 40 // up: 38, down: 40
if (ev.keyCode === 38 || ev.keyCode === 40) { if (ev.keyCode === 38 || ev.keyCode === 40) {
ev.preventDefault() ev.preventDefault()
return this.updateValue(ev.keyCode === 38 ? '+' : '-') return this.#updateValue(ev.keyCode === 38 ? '+' : '-')
} }
// 回车触发submit事件 // 回车触发submit事件
if (ev.keyCode === 13) { if (ev.keyCode === 13) {
ev.preventDefault() ev.preventDefault()
// 并发拦截 // 并发拦截
if (lazy && now - this.stamp < lazy) { if (lazy && now - this.#stamp < lazy) {
return return
} }
this.stamp = now this.#stamp = now
this.value = this.clapm(ev.target.value) this.value = this.#fix(ev.target.value)
this.$refs.input.value = this.value this.$refs.input.value = this.value
this.$emit('submit', { value: this.value }) this.$emit('submit', { value: this.value })
} }
} }
clapm(val) { #fix(val) {
const max = this.max ?? Number.MAX_SAFE_INTEGER let { max, min } = this
const min = this.min ?? Number.MIN_SAFE_INTEGER
return Math.min(max, Math.max(+val, min)) return Math.min(max, Math.max(+val, min))
} }
render() { render() {
return html` return html`
<div class="label"> <main class="container">
<span <button
data-act="-" data-act="-"
class=${this.min && this.value - this.step < this.min :disabled=${this.value <= this.min}
? 'disabled' @click=${this.#click}
: ''}
@click=${this.onClick}
>-</span
> >
-
</button>
<input <input
ref="input" ref="input"
value="0" maxlength="10"
maxlength="9"
disabled=${this.disabled} disabled=${this.disabled}
readonly=${this.readOnly} :readOnly=${this.readOnly}
autofocus=${this.autofocus} value=${this.value}
:value=${this.value} @change=${this.#changed}
@change=${this.onChange} @keydown=${this.#keydown}
@keydown=${this.onKeydown}
/> />
<span <button
data-act="+" data-act="+"
class=${this.max && this.value + this.step > this.max :disabled=${this.value >= this.max}
? 'disabled' @click=${this.#click}
: ''}
@click=${this.onClick}
>+</span
> >
</div> +
</button>
</main>
` `
} }
} }
WcNumber.reg('number') InputNumber.reg('number')