Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 19 additions & 12 deletions src/components/Form/FormItem/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -124,21 +124,28 @@ const Item: React.FC<HuiFormItemProps> = (props) => {

const copyChildren = () => {
if (React.isValidElement(children)) {
if (!Object.prototype.hasOwnProperty.call(children.props, 'onChange')) {
newProps.current.onChange = onChange
} else {
delete newProps.current.onChange
}
if (!Object.prototype.hasOwnProperty.call(children.props, 'value')) {
newProps.current.value = localValue
} else {
delete newProps.current.value
}
setNewPropsProperty('onChange', onChange)
setNewPropsProperty('value', localValue)
setNewPropsProperty('onInput', onChange)
return children && React.cloneElement(children as any, newProps.current)
}
return children
}

const setNewPropsProperty = (key: string, value: any = null) => {
if (React.isValidElement(children)) {
const hasPrototypeAttribute = Object.prototype.hasOwnProperty.call(
children.props,
key,
)
if (!hasPrototypeAttribute) {
newProps.current[key] = value
} else {
delete newProps.current[key]
}
}
}

const [implementAnimation] = useAnimationCss(
`${formItemPrefix}-animation`,
!!ruleText,
Expand All @@ -147,7 +154,7 @@ const Item: React.FC<HuiFormItemProps> = (props) => {
const validatorRules = useCallback(
async (value: string) => {
try {
const [css, text] = validatorField(
const [css, text] = await validatorField(
rule,
value,
renderType,
Expand All @@ -161,7 +168,7 @@ const Item: React.FC<HuiFormItemProps> = (props) => {
name: path,
}
} catch (error) {
throw new Error(error)
throw new Error(error as string)
}
},
[getFieldValue, path, renderType, rule],
Expand Down
41 changes: 30 additions & 11 deletions src/components/Form/FormItem/rules/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,14 @@ import {
validatorDigitText,
validatorIntegerText,
validatorRequireText,
validateInnerCustom,
} from '../../constants/field'

interface ValidatorType {
inner
rule
custom
innerCustomValidate
}

/**
Expand All @@ -32,19 +34,27 @@ const validatorInnerField = (value: string, itemType: keyof ItemType) => {
}
}

const validatorRule = (
const validatorRule = async (
rule: Rule,
value: string,
fieldType: keyof ItemType,
getFieldValue: any,
): {
): Promise<{
fieldState: boolean
validatorType: keyof ValidatorType
} => {
}> => {
const [defaultRuleTarget, customRuleFun] = rule || []
const { require, pattern } = defaultRuleTarget || {}
const { require, pattern, validator } = defaultRuleTarget || {}
let globalInputStatus = true

// 如果 rule 中存在自定义函数,那么他的优先级最高
if (validator && typeof validator === 'function') {
const validateMsg = await validateInnerCustom(value, rule)
return {
fieldState: !validateMsg,
validatorType: 'innerCustomValidate',
} as any
}
// 内部值检验
const innerCheckResult = value ? validatorInnerField(value, fieldType) : true
if (!innerCheckResult) {
Expand Down Expand Up @@ -80,7 +90,10 @@ const validatorRule = (
}
}

const validatorStyleInner = (type: keyof FieldType, value: string): [string, string] => {
const validatorStyleInner = (
type: keyof FieldType,
value: string,
): [string, string] => {
let str = ''
switch (type) {
case 'inputNumber':
Expand All @@ -95,16 +108,17 @@ const validatorStyleInner = (type: keyof FieldType, value: string): [string, str
return [errorCss, str]
}

const validatorStyle = (
const validatorStyle = async (
validatorType: keyof ValidatorType,
type: keyof FieldType,
value: string,
rule: Rule,
): [string, string] => {
) => {
switch (validatorType) {
case 'innerCustomValidate':
return [errorCss, await validateInnerCustom(value, rule)]
case 'custom':
return [errorCss, validatorRequireText(rule[0]?.message || '')]

case 'inner':
return validatorStyleInner(type, value)
case 'rule':
Expand All @@ -114,14 +128,19 @@ const validatorStyle = (
}
}

const validatorField = <T>(
const validatorField = async <T>(
rule: Rule,
value: string | undefined,
fieldType: keyof ItemType,
getFieldValue: T,
): string[] => {
): Promise<string[]> => {
if (typeof value === 'undefined') return [normalCss, '']
const { fieldState, validatorType } = validatorRule(rule, value, fieldType, getFieldValue)
const { fieldState, validatorType } = await validatorRule(
rule,
value,
fieldType,
getFieldValue,
)
if (fieldState) {
// 兼容下item里面的处理
return [normalCss, '']
Expand Down
18 changes: 18 additions & 0 deletions src/components/Form/constants/field.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,26 @@
import { Rule } from './formItem'

export const fieldPrefix = 'hui-form-item'
export const normalCss = `${fieldPrefix}-normal`
export const errorCss = `${fieldPrefix}-error`
export const disableCss = `${fieldPrefix}-disable`

export const validateInnerCustom = async (
value: string,
rule: Rule,
): Promise<string> => {
if (!rule || !rule.length) return ''
const [defaultRuleTarget] = rule
const { validator = null } = defaultRuleTarget
try {
if (typeof validator !== 'function') {
throw new Error('validator must be function')
}
return (await validator(value)) as unknown as string
} catch (err) {
return (err as Error)?.message || ''
}
}
export const validatorRequireText = (value: string): string =>
value || '当前选项必填'
export const validatorIntegerText = (value: string): string =>
Expand Down
5 changes: 5 additions & 0 deletions src/components/Form/constants/formItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,11 @@ export type DefaultRuleTarget = {
pattern?: RegExp
/** 文案 */
message?: string
/**
* @param value FormItem的值
* @param callback 自定义执行函数
*/
validator?: (value: any) => Promise<void | Error>
}

type RuleReg = (
Expand Down
22 changes: 16 additions & 6 deletions src/pages/Form/Form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ const InputPage: React.FC = () => {
const [localData, setLocalData] = useState({
sync: false,
account: '',
money: '',
password: '',
gender: '男',
disable: '',
Expand Down Expand Up @@ -132,6 +133,13 @@ const InputPage: React.FC = () => {
return ''
}

const validateMoney = (value: string) => {
if (!value) return Promise.reject(new Error('请填写金额数!'))
if (value === '123') return Promise.reject(new Error('金额数错误!'))
if (/^0/.test(value)) return Promise.reject(new Error('金额数不能为0!'))
return Promise.resolve()
}

const HuiFormItem = HuiForm.Item
return (
<View className='form-demo-page'>
Expand Down Expand Up @@ -175,13 +183,15 @@ const InputPage: React.FC = () => {
]}
tipsText='密码必须为6-10个字符之间'
>
<HuiInput
divider={false}
onInput={(e) => form.setFieldValue('password', e.detail.value)}
type='safe-password'
></HuiInput>
<HuiInput divider={false} type='safe-password'></HuiInput>
</HuiFormItem>
<HuiFormItem
rule={[{ require: true, validator: validateMoney }]}
label='支付金额'
name='money'
>
<HuiInput divider={false} />
</HuiFormItem>

<HuiFormItem
rule={[{ require: true }]}
label='是否同步信息'
Expand Down