Form 表單
由 LhForm + LhFormItem 組成的複合元件,提供資料驗證、錯誤提示、標籤對齊等能力。
基礎用法
import { useRef, useState } from 'react'
import { LhButton, LhForm, LhFormItem, LhInput, LhSelect } from '@lh-ui/react'
import type { LhFormInstance, LhFormRule } from '@lh-ui/react'
interface FormData {
name: string
style: string
}
const rules: Record<string, LhFormRule[]> = {
name: [{ required: true, message: '请输入作品名称', trigger: 'blur' }],
style: [{ required: true, message: '请选择画风', trigger: 'change' }],
}
export default function Demo() {
const [formData, setFormData] = useState<FormData>({ name: '', style: '' })
const formRef = useRef<LhFormInstance>(null)
const handleSubmit = async () => {
const valid = await formRef.current?.validate()
if (valid) alert(`提交成功:${formData.name} / ${formData.style}`)
}
const handleReset = () => {
formRef.current?.resetFields()
setFormData({ name: '', style: '' })
}
return (
<LhForm ref={formRef} model={formData} rules={rules} labelWidth="80px">
<LhFormItem label="作品名称" prop="name">
<LhInput
value={formData.name}
onChange={(val) => setFormData((prev) => ({ ...prev, name: val }))}
/>
</LhFormItem>
<LhFormItem label="画风" prop="style">
<LhSelect
value={formData.style}
onChange={(val) => setFormData((prev) => ({ ...prev, style: val as string }))}
options={[{ label: '水墨', value: 'ink' }]}
/>
</LhFormItem>
<LhFormItem>
<LhButton type="primary" onClick={handleSubmit}>提交</LhButton>
<LhButton onClick={handleReset}>重設</LhButton>
</LhFormItem>
</LhForm>
)
}
Form Props
| 屬性 | 說明 | 型別 | 預設值 |
|---|---|---|---|
| model | 表單資料物件(必填) | Record<string, unknown> | — |
| rules | 驗證規則,鍵為欄位名 | Record<string, LhFormRule[]> | — |
| labelWidth | 標籤寬度 | string | number | — |
| labelPosition | 標籤位置 | 'left' | 'right' | 'top' | 'right' |
| inline | 行內版面配置 | boolean | false |
| disabled | 停用全部子項 | boolean | false |
| size | 子項尺寸 | 'large' | 'middle' | 'small' | 跟隨 ConfigProvider |
| onSubmit | 原生提交事件(已 preventDefault) | (event: FormEvent) => void | — |
FormItem Props
| 屬性 | 說明 | 型別 | 預設值 |
|---|---|---|---|
| label | 標籤文案 | string | — |
| prop | 欄位名(支援點號路徑,對應 model 的鍵) | string | — |
| rules | item 級規則(同名時覆蓋 form 級) | LhFormRule[] | — |
| required | 必填星號(僅渲染標記,驗證語意由 rules 提供) | boolean | false |
| labelWidth | 覆蓋 form 級標籤寬度 | string | number | — |
| errorMessage | 自訂錯誤訊息 | string | — |
| showMessage | 顯示錯誤提示 | boolean | true |
LhFormRule
| 屬性 | 說明 | 型別 |
|---|---|---|
| required | 是否必填 | boolean |
| message | 驗證失敗訊息 | string |
| trigger | 觸發方式 | 'blur' | 'change' |
| validator | 自訂驗證函式(可傳回 Promise,非同步驗證會正確等待) | (value, model) => string | undefined | Promise<string | undefined> |
| min / max | 最小 / 最大值(數字或長度) | number |
| pattern | 正規驗證 | RegExp |
Form ref 方法
LhFormInstance(透過 forwardRef + useImperativeHandle 暴露):
| 方法 | 說明 | 傳回值 |
|---|---|---|
| validate | 驗證全部欄位 | Promise<boolean> |
| validateField | 驗證單一欄位 | Promise<boolean> |
| resetFields | 重設全部欄位到初始值 | void |
| resetField | 重設單一欄位 | void |
const formRef = useRef<LhFormInstance>(null)
const ok = await formRef.current?.validate()
本庫修正了 plus 的非同步驗證缺陷:plus 的 validateField 用 Promise.resolve(!message) 不會等待非同步 validator 的 Promise,非同步驗證恆傳回 true。React 版顯式等待 thenable 完成後再判定。詳見遷移指南。
LhFormItem 在 useEffect 內向 form 註冊驗證器,卸載時自動註銷。欄位無需預先宣告在 rules 裡——rules 裡沒有但 model 裡有的欄位,初始值會在註冊時補拍。
share 的 validateFormField 不解釋 trigger,觸發時機由本層接線:trigger: 'blur'(預設)
隨 FormItem 失焦驗證,trigger: 'change' 隨內 容區 change 驗證。未標註 trigger 的規則
只在失焦與 validate() 時運行,輸入過程中不會反覆報錯。
change 驗證取事件目標的新值而非 model 快照——React 的狀態更新與事件派發不在同一拍,
回頭讀 model 會滯後一拍。原生控制元件(input / textarea / 原生 select)的 change 事件
冒泡到內容區即被擷取;自訂控制元件沒有原生 change 事件(LhSelect 的選項點選只產生 click),
透過 FormItem 上下文的 validateChange(value) 主動帶著新值觸發。
resetFields() 除了把 model 還原到初始值快照,還會自增內部 resetVersion,各 FormItem
監聽到版本變化即清空自身錯誤態。外部受控狀態仍需自行同步(如 demo 裡的
setFormData(initial))——React 無法像 Vue 的 reactive 鏈路那樣代寫 model。
樣式
import '@lh-ui/react/style/form'