提交 d19ae9b4 编写于 作者: L liuyijun

feat: inputnumber组件开发完成

上级 228f8175
[{"/Users/liuyijun17/Desktop/jd-project/nutui/scripts/createComponentMode.js":"1"},{"size":7672,"mtime":1629095437672,"results":"2","hashOfConfig":"3"},{"filePath":"4","messages":"5","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},"7io7mh","/Users/liuyijun17/Desktop/jd-project/nutui/scripts/createComponentMode.js",[]]
\ No newline at end of file
......@@ -231,6 +231,16 @@
"sort": 2,
"show": true,
"author": "dsj"
},
{
"version": "1.0.0",
"name": "InputNumber",
"type": "component",
"cName": "数字输入框",
"desc": "通过点击按钮控制数字增减。",
"sort": 3,
"show": true,
"author": "swag~jun"
}
]
},
......
import React, { useState } from 'react'
import { InputNumber } from './inputnumber'
import Cell from '@/packages/cell'
import Toast from '@/packages/toast'
interface IValState {
val1: number | string
val2: number | string
val3: number | string
val4: number | string
val5: number | string
val6: number | string
val7: number | string
val8: number | string
}
const InputNumberDemo = () => {
const [inputState, setInputState] = useState<IValState>({
val1: 1,
val2: 0,
val3: 10,
val4: 0,
val5: 1,
val6: 5.5,
val7: 1,
val8: 1,
})
const overlimit = (e: MouseEvent) => {
console.log(e)
Toast.warn('超出限制事件触发')
}
const onChange = (value: string | number) => {
Toast.loading('异步演示 2 秒后更改')
setTimeout(() => {
inputState.val7 = Number(value)
setInputState({ ...inputState })
Toast.hide()
}, 2000)
}
return (
<>
<div className="demo">
<h2>基础用法</h2>
<Cell>
<InputNumber modelValue={inputState.val1} />
</Cell>
<h2>步长设置</h2>
<Cell>
<InputNumber modelValue={inputState.val2} step="5" />
</Cell>
<h2>限制输入范围</h2>
<Cell>
<InputNumber modelValue={inputState.val3} min="10" max="20" overlimit={overlimit} />
</Cell>
<h2>禁用操作</h2>
<Cell>
<InputNumber modelValue={inputState.val4} disabled />
</Cell>
<h2>只读禁用输入框</h2>
<Cell>
<InputNumber modelValue={inputState.val5} readonly />
</Cell>
<h2>支持小数</h2>
<Cell>
<InputNumber modelValue={inputState.val6} step="0.1" decimalPlaces="1" readonly />
</Cell>
<h2>支持异步修改</h2>
<Cell>
<InputNumber modelValue={inputState.val7} change={onChange} isAsync={true} />
</Cell>
<h2>自定义按钮大小</h2>
<Cell>
<InputNumber modelValue={inputState.val8} buttonSize="30" inputWidth="50" />
</Cell>
</div>
</>
)
}
export default InputNumberDemo
# InputNumber组件
### 介绍
基于 xxxxxxx
### 安装
## 代码演示
### 基础用法1
## API
### Props
| 参数 | 说明 | 类型 | 默认值 |
|--------------|----------------------------------|--------|------------------|
| name | 图标名称或图片链接 | String | - |
| color | 图标颜色 | String | - |
| size | 图标大小,如 '20px' '2em' '2rem' | String | - |
| class-prefix | 类名前缀,用于使用自定义图标 | String | 'nutui-iconfont' |
| tag | HTML 标签 | String | 'i' |
### Events
| 事件名 | 说明 | 回调参数 |
|--------|----------------|--------------|
| click | 点击图标时触发 | event: Event |
import { InputNumber } from './inputnumber'
export default InputNumber
.nut-inputnumber {
display: flex;
align-items: center;
&--disabled {
input {
color: $inputnumber-icon-void-color;
}
}
&__icon {
color: $inputnumber-icon-color;
font-size: $inputnumber-icon-size;
cursor: pointer;
&--disabled {
color: $inputnumber-icon-void-color;
cursor: not-allowed;
}
}
input,
&__text--readonly {
width: $inputnumber-input-width;
height: 100%;
text-align: center;
outline: none;
border: 0;
margin: 0 6px;
background-color: $inputnumber-input-background-color;
border-radius: $inputnumber-input-border-radius;
}
input::-webkit-outer-spin-button,
input::-webkit-inner-spin-button {
appearance: none;
}
}
import React, { useState, useEffect, FunctionComponent, ChangeEvent, FocusEvent } from 'react'
import Icon from '@/packages/icon'
import classNames from 'classnames'
import bem from '@/utils/bem'
import './inputnumber.scss'
export interface InputNumberProps {
disabled: boolean
buttonSize: string | number
min: string | number
max: string | number
inputWidth: string | number
readonly: boolean
modelValue: string | number
step: string | number
decimalPlaces: string | number
isAsync: boolean
add: (e: MouseEvent) => void
reduce: (e: MouseEvent) => void
overlimit: (e: MouseEvent) => void
blur: (e: ChangeEvent<HTMLInputElement>) => void
focus: (e: FocusEvent<HTMLInputElement>) => void
change: (param: string | number, e: MouseEvent | ChangeEvent<HTMLInputElement>) => void
}
const defaultProps = {
disabled: false,
buttonSize: '',
min: 1,
max: 9999,
inputWidth: '',
readonly: false,
modelValue: 0,
step: 1,
decimalPlaces: 0,
isAsync: false,
} as InputNumberProps
function pxCheck(value: string | number): string {
return Number.isNaN(Number(value)) ? String(value) : `${value}px`
}
export const InputNumber: FunctionComponent<
Partial<InputNumberProps> & React.HTMLAttributes<HTMLDivElement>
> = (props) => {
const {
children,
disabled,
buttonSize,
min,
max,
inputWidth,
readonly,
modelValue,
decimalPlaces,
step,
isAsync,
add,
reduce,
change,
overlimit,
blur,
focus,
} = {
...defaultProps,
...props,
}
const [inputValue, setInputValue] = useState(modelValue)
useEffect(() => {
setInputValue(modelValue)
}, [modelValue])
const b = bem('inputnumber')
const addAllow = (value = Number(inputValue)) => {
return value < Number(max) && !disabled
}
const reduceAllow = (value = Number(inputValue)) => {
return value > Number(min) && !disabled
}
const classes = classNames(b(''), {
[`${b('')}--disabled`]: disabled,
})
const iconMinusClasses = classNames('nut-inputnumber__icon', {
'nut-inputnumber__icon--disabled': !reduceAllow(),
})
const iconAddClasses = classNames('nut-inputnumber__icon', {
'nut-inputnumber__icon--disabled': !addAllow(),
})
const fixedDecimalPlaces = (v: string | number): string => {
return Number(v).toFixed(Number(decimalPlaces))
}
const emitChange = (value: string | number, e: MouseEvent | ChangeEvent<HTMLInputElement>) => {
const output_value: number | string = fixedDecimalPlaces(value)
change && change(output_value, e)
if (!isAsync) {
setInputValue(output_value)
}
}
const reduceNumber = (e: MouseEvent) => {
reduce && reduce(e)
if (reduceAllow()) {
let output_value = Number(inputValue) - Number(step)
emitChange(output_value, e)
} else {
overlimit && overlimit(e)
}
}
const addNumber = (e: MouseEvent) => {
add && add(e)
if (addAllow()) {
const output_value = Number(inputValue) + Number(step)
emitChange(output_value, e)
} else {
overlimit && overlimit(e)
}
}
const changeValue = (e: ChangeEvent<HTMLInputElement>) => {
const input = e.target as HTMLInputElement
change && change(input.valueAsNumber, e)
if (!isAsync) {
if (Number.isNaN(input.valueAsNumber)) {
setInputValue(inputValue)
} else {
setInputValue(input.valueAsNumber)
}
}
}
const focusValue = (e: FocusEvent<HTMLInputElement>) => {
if (disabled) return
if (readonly) return
focus && focus(e)
}
const burValue = (e: ChangeEvent<HTMLInputElement>) => {
if (disabled) return
if (readonly) return
const input = e.target as HTMLInputElement
let value = input.valueAsNumber
if (value < Number(min)) {
value = Number(min)
} else if (value > Number(max)) {
value = Number(max)
}
emitChange(value, e)
blur && blur(e)
}
return (
<div className={classes} style={{ height: pxCheck(buttonSize) }}>
<Icon className={iconMinusClasses} size={buttonSize} name="minus" click={reduceNumber} />
<input
type="number"
min={min}
max={max}
style={{ width: pxCheck(inputWidth) }}
disabled={disabled}
readOnly={readonly}
value={inputValue}
onInput={changeValue}
onBlur={burValue}
onFocus={focusValue}
/>
<Icon className={iconAddClasses} size={buttonSize} name="plus" click={addNumber} />
</div>
)
}
InputNumber.defaultProps = defaultProps
InputNumber.displayName = 'NutInputNumber'
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册