4、第一个FormalNode实例:创建简单的表单节点、定义基础属性、输出节点结构。
好,咱们直接动手。前面聊了那么多理论,现在该写点真东西了。
这一节,我会带你创建一个最简单的 FormalNode 实例。说白了,就是先搭一个表单的“骨架”,看看它到底长什么样。
4.1 从零开始:创建一个表单节点
我个人习惯,在开始一个新项目或新模块时,先不急着写复杂的逻辑。先定义一个最基础的对象,看看它的结构是否合理。
在 FormalNode 里,一个表单节点就是一个对象。它包含了这个字段的所有“元信息”。
来看代码:
// 创建一个最简单的表单节点
const userNameNode = {
// 节点的唯一标识
name: 'userName',
// 节点的类型
type: 'string',
// 节点的标签(给用户看的)
label: '用户名',
// 节点的值
value: '',
// 节点的验证规则
rules: [],
// 节点的错误信息
error: null,
// 节点是否被修改过
dirty: false,
// 节点是否被触摸过(比如用户点击过输入框)
touched: false
};
console.log(userNameNode);
你看,这就是一个最原始的节点。它没有依赖任何库,就是一个纯粹的 JavaScript 对象。
我在项目中遇到过不少新手,一上来就把所有逻辑塞进一个巨大的对象里,结果后期维护起来特别痛苦。所以,我建议你从一开始就把结构定义清楚。
4.2 定义基础属性:每个节点都该有的“身份证”
刚才那个例子里的属性,其实都是基础属性。咱们来拆解一下,每个属性是干嘛用的。
| 属性名 | 类型 | 说明 |
|---|---|---|
name |
string | 节点的唯一标识。在整个表单里,不能重复。 |
type |
string | 字段类型。比如 string、number、email 等。 |
label |
string | 展示给用户的文本。比如“用户名”、“密码”。 |
value |
any | 当前存储的值。初始为空字符串或 null。 |
rules |
array | 验证规则列表。每个规则是一个函数或对象。 |
error |
string | null | 验证失败时的错误信息。没有错误就是 null。 |
dirty |
boolean | 用户是否修改过这个字段的值。 |
touched |
boolean | 用户是否“触碰”过这个字段。比如点击输入框又离开。 |
嗯,这里要注意。很多表单库会把 dirty 和 touched 混为一谈。其实不一样。
- dirty:值变了就算。哪怕你改了一个字符又改回来,它也是
true。 - touched:用户交互过就算。比如你点了输入框,但没输入任何内容,它也是
true。
我曾经踩过一个坑:只判断 dirty 来决定是否显示错误。结果用户刚打开页面,什么都没做,错误就冒出来了。用户体验极差。后来我改成同时判断 touched,才解决了这个问题。
4.3 输出节点结构:看看它到底长什么样
定义好了,咱们把它打印出来看看。你想想看,一个真实的表单节点,在内存里到底是什么样子?
// 创建一个稍微丰富一点的节点
const emailNode = {
name: 'email',
type: 'email',
label: '电子邮箱',
value: 'test@example.com',
rules: [
{ required: true, message: '邮箱不能为空' },
{ pattern: /^[^\s@]+@[^\s@]+\.[^\s@]+$/, message: '邮箱格式不正确' }
],
error: null,
dirty: false,
touched: false
};
// 输出节点结构
console.log(JSON.stringify(emailNode, null, 2));
输出结果是这样的:
{
"name": "email",
"type": "email",
"label": "电子邮箱",
"value": "test@example.com",
"rules": [
{
"required": true,
"message": "邮箱不能为空"
},
{
"pattern": {},
"message": "邮箱格式不正确"
}
],
"error": null,
"dirty": false,
"touched": false
}
看到没?rules 是一个数组,里面每个元素都是一个规则对象。每个规则对象至少包含一个 message 属性,用于在验证失败时提示用户。
这里有个小细节:pattern 在 JSON 序列化时变成了 {}。这是因为正则表达式对象在 JSON.stringify 时会被转换成空对象。如果你需要完整保留规则,建议用自定义的序列化方法。不过咱们现在只是看结构,不影响理解。
核心要点:一个 FormalNode 实例,本质上就是一个“自描述”的对象。它知道自己叫什么、是什么类型、当前值是什么、该怎么验证、有没有出错。
4.4 用 SVG 画一张节点结构图
光看代码可能还不够直观。我画了一张图,帮你把整个结构串起来。
小技巧:在实际项目中,我习惯把 dirty 和 touched 合并成一个 status 枚举。比如 status: 'idle' | 'focused' | 'changed' | 'submitted'。这样状态更清晰,也更容易做条件判断。不过对于初学者,先分开理解会更直观。
4.5 为什么这样设计?
你可能会问:为什么非要搞这么多个属性?直接一个 value 不就行了吗?
其实,表单的核心痛点不是“存值”,而是“状态管理”。
- 用户有没有改过?→
dirty - 用户有没有看过?→
touched - 验证过了没有?→
error - 该怎么验证?→
rules
这些状态,缺一个,你的表单体验就会出问题。我见过太多项目,因为没区分 dirty 和 touched,导致表单验证时机乱七八糟。
注意:不要试图把所有逻辑都塞进一个 value 里。比如有人喜欢用 value: { text: '', error: null, dirty: false }。这样虽然也能用,但后期扩展起来非常痛苦。每个属性各司其职,才是正道。
好了,第一个 FormalNode 实例就讲到这里。你现在应该能自己创建一个简单的表单节点,并且理解每个属性的含义了。下一节,我们会在这个基础上,给它加上验证逻辑。
公众号:蓝海资料掘金营,微信deep3321