iter(g280): 表单项支持条件显示
This commit is contained in:
+8
-2
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"$schema": "ui-arch-registry-index/0.1",
|
"$schema": "ui-arch-registry-index/0.1",
|
||||||
"generatedAt": "2026-10-26T15:05:05.398Z",
|
"generatedAt": "2026-10-26T15:06:03.807Z",
|
||||||
"repoRoot": ".",
|
"repoRoot": ".",
|
||||||
"packages": [
|
"packages": [
|
||||||
{
|
{
|
||||||
@@ -1988,6 +1988,11 @@
|
|||||||
"t": "number",
|
"t": "number",
|
||||||
"d": "多列表单里本字段占几列(如整宽的多行备注);单列布局或窄屏下自动退回整行"
|
"d": "多列表单里本字段占几列(如整宽的多行备注);单列布局或窄屏下自动退回整行"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"n": "(formItem)visible",
|
||||||
|
"t": "Signal<boolean>",
|
||||||
|
"d": "条件显示信号:为假时整项隐藏且不参与校验(未显示的字段不该拦住提交)"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"n": "onReset",
|
"n": "onReset",
|
||||||
"t": "() => void",
|
"t": "() => void",
|
||||||
@@ -2020,7 +2025,8 @@
|
|||||||
"formItem 返回 { el, validate, validateAsync } 句柄:validate 只跑同步规则(供 blur/input 即时反馈),validateAsync 逐条 await 供 form 聚合提交",
|
"formItem 返回 { el, validate, validateAsync } 句柄:validate 只跑同步规则(供 blur/input 即时反馈),validateAsync 逐条 await 供 form 聚合提交",
|
||||||
"需要给字段加格式说明就传 hint:平时显示在控件下方,校验失败时自动让位给错误文案,同一位置不堆两行",
|
"需要给字段加格式说明就传 hint:平时显示在控件下方,校验失败时自动让位给错误文案,同一位置不堆两行",
|
||||||
"字段多的编辑页传 columns: 2 或 3 走多列栅格:列间距与窄屏堆叠沿用 grid,按钮区始终整行;单列表单不要传(默认 1)",
|
"字段多的编辑页传 columns: 2 或 3 走多列栅格:列间距与窄屏堆叠沿用 grid,按钮区始终整行;单列表单不要传(默认 1)",
|
||||||
"多列表单里想整宽就传 span:formItem({ span: 2 }, textarea(...)) 会占满两列,窄屏单列时自动忽略跨列(否则会撑出横向滚动)"
|
"多列表单里想整宽就传 span:formItem({ span: 2 }, textarea(...)) 会占满两列,窄屏单列时自动忽略跨列(否则会撑出横向滚动)",
|
||||||
|
"字段要按另一个字段的值决定是否出现(选了「其他」才出现输入框),给 formItem 传 visible 信号:隐藏项自动清掉错误态并退出校验,不用自己在 items 数组里增删"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
+3
-1
@@ -1,6 +1,6 @@
|
|||||||
# @ui-arch 组件库 Agent 文档(无图形版)
|
# @ui-arch 组件库 Agent 文档(无图形版)
|
||||||
|
|
||||||
> 自动生成于 2026-10-26T15:05:05.398Z,数据源:各包 ua.manifest.json,勿手改。人类版文档站:apps/docs/index.html。
|
> 自动生成于 2026-10-26T15:06:03.807Z,数据源:各包 ua.manifest.json,勿手改。人类版文档站:apps/docs/index.html。
|
||||||
> 组件 = 普通函数,传 props 返回 DOM;状态用 signal 双向绑定:读 signal() 写 signal(v)。
|
> 组件 = 普通函数,传 props 返回 DOM;状态用 signal 双向绑定:读 signal() 写 signal(v)。
|
||||||
|
|
||||||
## 快速上手
|
## 快速上手
|
||||||
@@ -976,6 +976,7 @@ const open = signal(false); drawer({ title: '详情', open, width: 360, onClose:
|
|||||||
- (formItem)validateOn(默认 blur):'input' | 'blur' | 'submit' —— 校验时机;缺省 blur(输入时自动清已报错误)
|
- (formItem)validateOn(默认 blur):'input' | 'blur' | 'submit' —— 校验时机;缺省 blur(输入时自动清已报错误)
|
||||||
- (formItem)hint:string —— 控件下方辅助说明(格式提示等);报错时让位给错误文案
|
- (formItem)hint:string —— 控件下方辅助说明(格式提示等);报错时让位给错误文案
|
||||||
- (formItem)span:number —— 多列表单里本字段占几列(如整宽的多行备注);单列布局或窄屏下自动退回整行
|
- (formItem)span:number —— 多列表单里本字段占几列(如整宽的多行备注);单列布局或窄屏下自动退回整行
|
||||||
|
- (formItem)visible:Signal<boolean> —— 条件显示信号:为假时整项隐藏且不参与校验(未显示的字段不该拦住提交)
|
||||||
- onReset:() => void —— 重置按钮点击回调;组件不自行清空字段,由调用方重置信号;不传 resetText 不渲染按钮
|
- onReset:() => void —— 重置按钮点击回调;组件不自行清空字段,由调用方重置信号;不传 resetText 不渲染按钮
|
||||||
- onError(回调):(count: number) => void —— 校验不通过时的回调,参数为不通字段数(适合埋点或顶部提示)
|
- onError(回调):(count: number) => void —— 校验不通过时的回调,参数为不通字段数(适合埋点或顶部提示)
|
||||||
- errorSummary:boolean —— 是否在表单顶部显示「有 N 项需要修改」汇总条;缺省 true,自带错误 UI 时传 false
|
- errorSummary:boolean —— 是否在表单顶部显示「有 N 项需要修改」汇总条;缺省 true,自带错误 UI 时传 false
|
||||||
@@ -1002,6 +1003,7 @@ const name = signal(''); const f = form({ onSubmit: submit }, [formItem({ label:
|
|||||||
12. 需要给字段加格式说明就传 hint:平时显示在控件下方,校验失败时自动让位给错误文案,同一位置不堆两行
|
12. 需要给字段加格式说明就传 hint:平时显示在控件下方,校验失败时自动让位给错误文案,同一位置不堆两行
|
||||||
13. 字段多的编辑页传 columns: 2 或 3 走多列栅格:列间距与窄屏堆叠沿用 grid,按钮区始终整行;单列表单不要传(默认 1)
|
13. 字段多的编辑页传 columns: 2 或 3 走多列栅格:列间距与窄屏堆叠沿用 grid,按钮区始终整行;单列表单不要传(默认 1)
|
||||||
14. 多列表单里想整宽就传 span:formItem({ span: 2 }, textarea(...)) 会占满两列,窄屏单列时自动忽略跨列(否则会撑出横向滚动)
|
14. 多列表单里想整宽就传 span:formItem({ span: 2 }, textarea(...)) 会占满两列,窄屏单列时自动忽略跨列(否则会撑出横向滚动)
|
||||||
|
15. 字段要按另一个字段的值决定是否出现(选了「其他」才出现输入框),给 formItem 传 visible 信号:隐藏项自动清掉错误态并退出校验,不用自己在 items 数组里增删
|
||||||
|
|
||||||
现场演示:apps/docs/demo.html#sec-formlab
|
现场演示:apps/docs/demo.html#sec-formlab
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { h } from '@ui-arch/frame';
|
import { effect, h } from '@ui-arch/frame';
|
||||||
import { button } from './button.js';
|
import { button } from './button.js';
|
||||||
import { grid } from './grid.js';
|
import { grid } from './grid.js';
|
||||||
import type { FormItemHandle, FormItemProps, FormProps, FormRule } from './types.js';
|
import type { FormItemHandle, FormItemProps, FormProps, FormRule } from './types.js';
|
||||||
@@ -40,6 +40,8 @@ export function formItem(props: FormItemProps, control: HTMLElement): FormItemHa
|
|||||||
const label = h('label', { class: 'ua-form-label' }, props.label, props.required ? h('i', { class: 'ua-form-req' }, '*') : null);
|
const label = h('label', { class: 'ua-form-label' }, props.label, props.required ? h('i', { class: 'ua-form-req' }, '*') : null);
|
||||||
const el = h('div', { class: 'ua-form-item' }, label, h('div', { class: 'ua-form-control' }, control, hint, error));
|
const el = h('div', { class: 'ua-form-item' }, label, h('div', { class: 'ua-form-control' }, control, hint, error));
|
||||||
if (props.span) el.style.gridColumn = `span ${props.span}`; // 多列布局里跨列;单列容器下由 CSS 还原为整行
|
if (props.span) el.style.gridColumn = `span ${props.span}`; // 多列布局里跨列;单列容器下由 CSS 还原为整行
|
||||||
|
// 条件显示:隐藏时顺带清掉错误态,否则「看不见的红框」会拦住提交
|
||||||
|
if (props.visible) effect(() => { el.hidden = !props.visible?.(); if (el.hidden) paint(null); });
|
||||||
let seq = 0; // 校验轮次:异步结论回来时若已有更新的一轮,丢弃旧结果(防乱序覆盖)
|
let seq = 0; // 校验轮次:异步结论回来时若已有更新的一轮,丢弃旧结果(防乱序覆盖)
|
||||||
|
|
||||||
/*** 错误态落点:控件根 + 内部原生控件,保证 select / checkbox 这类包裹式控件也能标红 ***/
|
/*** 错误态落点:控件根 + 内部原生控件,保证 select / checkbox 这类包裹式控件也能标红 ***/
|
||||||
@@ -58,6 +60,7 @@ export function formItem(props: FormItemProps, control: HTMLElement): FormItemHa
|
|||||||
|
|
||||||
/*** 同步校验:异步规则不结论,保证 blur / input 路径不被 Promise 拖慢 ***/
|
/*** 同步校验:异步规则不结论,保证 blur / input 路径不被 Promise 拖慢 ***/
|
||||||
const validate = (): string | null => {
|
const validate = (): string | null => {
|
||||||
|
if (el.hidden) return null; // 隐藏项不参与校验:没显示的字段不该拦住提交
|
||||||
const value = props.value();
|
const value = props.value();
|
||||||
let msg: string | null = null;
|
let msg: string | null = null;
|
||||||
for (const rule of rules) {
|
for (const rule of rules) {
|
||||||
@@ -70,6 +73,7 @@ export function formItem(props: FormItemProps, control: HTMLElement): FormItemHa
|
|||||||
|
|
||||||
/*** 异步校验:按序 await 每条规则,结论按轮次取舍,过期结果不动 UI ***/
|
/*** 异步校验:按序 await 每条规则,结论按轮次取舍,过期结果不动 UI ***/
|
||||||
const validateAsync = async (): Promise<string | null> => {
|
const validateAsync = async (): Promise<string | null> => {
|
||||||
|
if (el.hidden) return null; // 隐藏项不参与异步校验,与同步版同一口径
|
||||||
seq += 1;
|
seq += 1;
|
||||||
const mine = seq; // 本轮编号
|
const mine = seq; // 本轮编号
|
||||||
const value = props.value();
|
const value = props.value();
|
||||||
|
|||||||
@@ -462,6 +462,7 @@ export interface FormItemProps {
|
|||||||
validateOn?: 'input' | 'blur' | 'submit'; // 校验时机;缺省 blur
|
validateOn?: 'input' | 'blur' | 'submit'; // 校验时机;缺省 blur
|
||||||
hint?: string; // 控件下方辅助说明(格式提示等);报错时让位给错误文案
|
hint?: string; // 控件下方辅助说明(格式提示等);报错时让位给错误文案
|
||||||
span?: number; // 多列表单里本字段占几列(如整宽的多行文本);单列布局下无效
|
span?: number; // 多列表单里本字段占几列(如整宽的多行文本);单列布局下无效
|
||||||
|
visible?: Signal<boolean>; // 条件显示信号:为假时整项隐藏且不参与校验(未显示的字段不该拦住提交)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*** 表单字段句柄:form 聚合校验用 ***/
|
/*** 表单字段句柄:form 聚合校验用 ***/
|
||||||
|
|||||||
@@ -1859,6 +1859,11 @@
|
|||||||
"t": "number",
|
"t": "number",
|
||||||
"d": "多列表单里本字段占几列(如整宽的多行备注);单列布局或窄屏下自动退回整行"
|
"d": "多列表单里本字段占几列(如整宽的多行备注);单列布局或窄屏下自动退回整行"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"n": "(formItem)visible",
|
||||||
|
"t": "Signal<boolean>",
|
||||||
|
"d": "条件显示信号:为假时整项隐藏且不参与校验(未显示的字段不该拦住提交)"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"n": "onReset",
|
"n": "onReset",
|
||||||
"t": "() => void",
|
"t": "() => void",
|
||||||
@@ -1891,7 +1896,8 @@
|
|||||||
"formItem 返回 { el, validate, validateAsync } 句柄:validate 只跑同步规则(供 blur/input 即时反馈),validateAsync 逐条 await 供 form 聚合提交",
|
"formItem 返回 { el, validate, validateAsync } 句柄:validate 只跑同步规则(供 blur/input 即时反馈),validateAsync 逐条 await 供 form 聚合提交",
|
||||||
"需要给字段加格式说明就传 hint:平时显示在控件下方,校验失败时自动让位给错误文案,同一位置不堆两行",
|
"需要给字段加格式说明就传 hint:平时显示在控件下方,校验失败时自动让位给错误文案,同一位置不堆两行",
|
||||||
"字段多的编辑页传 columns: 2 或 3 走多列栅格:列间距与窄屏堆叠沿用 grid,按钮区始终整行;单列表单不要传(默认 1)",
|
"字段多的编辑页传 columns: 2 或 3 走多列栅格:列间距与窄屏堆叠沿用 grid,按钮区始终整行;单列表单不要传(默认 1)",
|
||||||
"多列表单里想整宽就传 span:formItem({ span: 2 }, textarea(...)) 会占满两列,窄屏单列时自动忽略跨列(否则会撑出横向滚动)"
|
"多列表单里想整宽就传 span:formItem({ span: 2 }, textarea(...)) 会占满两列,窄屏单列时自动忽略跨列(否则会撑出横向滚动)",
|
||||||
|
"字段要按另一个字段的值决定是否出现(选了「其他」才出现输入框),给 formItem 传 visible 信号:隐藏项自动清掉错误态并退出校验,不用自己在 items 数组里增删"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user