Skip to content

Form 表单

表单容器组件,支持表单验证、字段管理、错误提示等功能。

基础表单

简单的表单验证示例。

html
<form class="sa-form" id="basicForm" style="max-width: 600px;" data-label-position="right" data-label-width="100px">
  <div class="sa-form-item">
    <label class="sa-form-item__label">用户名</label>
    <div class="sa-form-item__content">
      <div class="sa-input" 
           data-prop="username"
           data-placeholder="请输入用户名"
           data-clearable="true"></div>
    </div>
  </div>
  <div class="sa-form-item">
    <label class="sa-form-item__label">邮箱</label>
    <div class="sa-form-item__content">
      <div class="sa-input" 
           data-prop="email"
           data-placeholder="请输入邮箱"
           data-type="email"
           data-clearable="true"></div>
    </div>
  </div>
  <div style="margin-top: 20px; display: flex; gap: 10px;">
    <button type="submit" class="sa-button sa-button--primary">提交</button>
    <button type="button" class="sa-button" id="resetBtn1">重置</button>
    <button type="button" class="sa-button" id="validateBtn1">验证</button>
  </div>
</form>

<script>
const basicForm = new SaForm('#basicForm', {
  rules: {
    username: [
      { required: true, message: '用户名不能为空' },
      { min: 3, max: 20, message: '用户名长度在 3 到 20 个字符' }
    ],
    email: [
      { required: true, message: '邮箱不能为空' },
      { type: 'email', message: '请输入正确的邮箱格式' }
    ]
  }
});

SA.init('body');
</script>
加载 SanoUI 组件中...
            
          

完整验证规则

包含多种验证规则的表单,演示 required、min、max、type、pattern 和自定义 validator 等验证规则。

html
<form class="sa-form" id="fullForm" style="max-width: 600px;" data-label-position="right" data-label-width="100px">
  <div class="sa-form-item">
    <label class="sa-form-item__label">用户名</label>
    <div class="sa-form-item__content">
      <div class="sa-input" 
           data-prop="username"
           data-placeholder="3-20个字符"
           data-clearable="true"></div>
    </div>
  </div>
  <div class="sa-form-item">
    <label class="sa-form-item__label">密码</label>
    <div class="sa-form-item__content">
      <div class="sa-input" 
           data-prop="password"
           data-placeholder="至少6个字符"
           data-type="password"
           data-show-password="true"
           data-clearable="false"></div>
    </div>
  </div>
  <div class="sa-form-item">
    <label class="sa-form-item__label">确认密码</label>
    <div class="sa-form-item__content">
      <div class="sa-input" 
           data-prop="confirmPassword"
           data-placeholder="再次输入密码"
           data-type="password"
           data-show-password="true"
           data-clearable="false"></div>
    </div>
  </div>
  <div class="sa-form-item">
    <label class="sa-form-item__label">邮箱</label>
    <div class="sa-form-item__content">
      <div class="sa-input" 
           data-prop="email"
           data-placeholder="example@email.com"
           data-type="email"
           data-clearable="true"></div>
    </div>
  </div>
  <div class="sa-form-item">
    <label class="sa-form-item__label">手机号</label>
    <div class="sa-form-item__content">
      <div class="sa-input" 
           data-prop="phone"
           data-placeholder="11位手机号"
           data-clearable="true"></div>
    </div>
  </div>
  <div style="margin-top: 20px; display: flex; gap: 10px;">
    <button type="submit" class="sa-button sa-button--primary">提交</button>
    <button type="button" class="sa-button" id="resetBtn2">重置</button>
    <button type="button" class="sa-button" id="clearValidateBtn">清除验证</button>
  </div>
</form>

<script>
const fullForm = new SaForm('#fullForm', {
  rules: {
    username: [
      { required: true, message: '用户名不能为空' },
      { min: 3, max: 20, message: '用户名长度在 3 到 20 个字符' }
    ],
    password: [
      { required: true, message: '密码不能为空' },
      { min: 6, message: '密码长度不能少于 6 个字符' }
    ],
    confirmPassword: [
      { required: true, message: '请确认密码' },
      {
        validator: (rule, value, allValues) => {
          if (value !== allValues.password) {
            return '两次输入的密码不一致';
          }
          return true;
        },
        message: '两次输入的密码不一致'
      }
    ],
    email: [
      { required: true, message: '邮箱不能为空' },
      { type: 'email', message: '请输入正确的邮箱格式' }
    ],
    phone: [
      { required: true, message: '手机号不能为空' },
      { pattern: /^1[3-9]\d{9}$/, message: '请输入正确的手机号格式' }
    ]
  }
});

SA.init('body');
</script>
加载 SanoUI 组件中...
            
          

不同布局

标签在上方

使用 data-label-position="top" 将标签放在上方。

html
<form class="sa-form" id="topForm" style="max-width: 600px;" data-label-position="top">
  <div class="sa-form-item">
    <label class="sa-form-item__label">用户名</label>
    <div class="sa-form-item__content">
      <div class="sa-input" 
           data-prop="username"
           data-placeholder="请输入用户名"
           data-clearable="true"></div>
    </div>
  </div>
  <div class="sa-form-item">
    <label class="sa-form-item__label">邮箱</label>
    <div class="sa-form-item__content">
      <div class="sa-input" 
           data-prop="email"
           data-placeholder="请输入邮箱"
           data-type="email"
           data-clearable="true"></div>
    </div>
  </div>
</form>

<script>
const topForm = new SaForm('#topForm');
SA.init('body');
</script>
加载 SanoUI 组件中...
            
          

标签在左侧

使用 data-label-position="left"data-label-width="100px" 将标签放在左侧。

html
<form class="sa-form" id="leftForm" style="max-width: 600px;" data-label-position="left" data-label-width="100px">
  <div class="sa-form-item">
    <label class="sa-form-item__label">用户名</label>
    <div class="sa-form-item__content">
      <div class="sa-input" 
           data-prop="username"
           data-placeholder="请输入用户名"
           data-clearable="true"></div>
    </div>
  </div>
  <div class="sa-form-item">
    <label class="sa-form-item__label">邮箱</label>
    <div class="sa-form-item__content">
      <div class="sa-input" 
           data-prop="email"
           data-placeholder="请输入邮箱"
           data-type="email"
           data-clearable="true"></div>
    </div>
  </div>
</form>

<script>
const leftForm = new SaForm('#leftForm');
SA.init('body');
</script>
加载 SanoUI 组件中...
            
          

自动初始化

使用 SA.init() 可以自动初始化表单内的所有组件,包括 form、input、button 等。

html
<form class="sa-form" id="autoInitForm" style="max-width: 600px;" data-label-position="right" data-label-width="100px">
  <div class="sa-form-item">
    <label class="sa-form-item__label">用户名</label>
    <div class="sa-form-item__content">
      <div class="sa-input" 
           data-prop="username"
           data-placeholder="请输入用户名"
           data-value="admin"
           data-clearable="true"></div>
    </div>
  </div>
  <div class="sa-form-item">
    <label class="sa-form-item__label">密码</label>
    <div class="sa-form-item__content">
      <div class="sa-input" 
           data-prop="password"
           data-placeholder="请输入密码"
           data-type="password"
           data-show-password="true"
           data-clearable="false"></div>
    </div>
  </div>
  <div style="margin-top: 20px; display: flex; gap: 10px;">
    <button type="submit" class="sa-button sa-button--primary">提交</button>
    <button type="button" class="sa-button" id="getValuesBtn">获取值</button>
  </div>
</form>

<script>
// 使用 SA.init() 自动初始化所有组件
const page = SA.init('body');

// 手动创建表单实例并配置验证规则
const autoInitForm = new SaForm('#autoInitForm', {
  rules: {
    username: [
      { required: true, message: '用户名不能为空' }
    ],
    password: [
      { required: true, message: '密码不能为空' },
      { min: 6, message: '密码长度不能少于 6 个字符' }
    ]
  }
});
</script>
加载 SanoUI 组件中...
            
          

API

构造函数

javascript
new SaForm(container, config)

参数

参数说明类型默认值
container容器选择器或元素string | HTMLElement-
config配置选项SaFormOptions{}

配置选项

参数说明类型默认值
rules验证规则对象Object<string, Array<Rule>>{}
labelPosition标签位置'left' | 'right' | 'top''right'
labelWidth标签宽度string'100px'
labelSuffix标签后缀string''
inline是否行内表单booleanfalse
disabled是否禁用表单booleanfalse
size表单尺寸'large' | 'default' | 'small''default'
showMessage是否显示错误消息booleantrue

验证规则 (Rule)

参数说明类型默认值
required是否必填booleanfalse
message错误提示信息string-
min最小长度(字符串)或最小值(数字)number-
max最大长度(字符串)或最大值(数字)number-
type类型验证'string' | 'number' | 'email' | 'url' | 'tel'-
pattern正则表达式验证RegExp-
validator自定义验证函数function(rule, value, allValues): boolean | string-
trigger触发验证的时机'blur' | 'change''blur'

Data 属性

属性说明类型默认值
data-label-position标签位置string'right'
data-label-width标签宽度string'100px'
data-label-suffix标签后缀string''
data-inline是否行内表单booleanfalse
data-disabled是否禁用booleanfalse
data-size表单尺寸string'default'
data-show-message是否显示错误消息booleantrue

方法

方法名说明参数返回值
registerField(prop, element, rules?)注册表单字段prop: string - 字段属性名
element: HTMLElement - 字段元素
rules?: Array<Rule> - 验证规则
this
validate(props?)验证表单props?: Array<string> - 要验证的字段列表Promise<Object> - 验证通过返回表单数据,失败返回错误对象
validateField(prop)验证单个字段prop: string - 字段属性名Promise<boolean>
getFieldsValue(props?)获取表单数据props?: Array<string> - 要获取的字段列表Object - 表单数据对象
setFieldsValue(values)设置表单字段值values: Object - 字段值对象 { prop: value }void
resetFields(props?)重置表单字段props?: Array<string> - 要重置的字段列表this
clearValidate(props?)清除字段验证错误props?: string | Array<string> - 字段属性名或数组this
destroy()销毁实例-void

字段注册

表单字段需要通过 data-prop 属性注册:

html
<div class="sa-input" data-prop="username"></div>

或手动注册:

javascript
form.registerField('username', element, [
  { required: true, message: '用户名不能为空' }
]);

实际使用场景

场景 1:用户注册表单

完整的用户注册表单,包含用户名、密码、确认密码、邮箱等字段的验证。

html
<form class="sa-form" id="register-form" style="max-width: 500px;" data-label-position="right" data-label-width="120px">
  <div class="sa-form-item">
    <label class="sa-form-item__label">用户名</label>
    <div class="sa-form-item__content">
      <div class="sa-input" 
           data-prop="username"
           data-placeholder="3-20个字符,支持字母、数字、下划线"
           data-clearable="true"
           style="width: 100%;"></div>
    </div>
  </div>
  
  <div class="sa-form-item">
    <label class="sa-form-item__label">密码</label>
    <div class="sa-form-item__content">
      <div class="sa-input" 
           data-prop="password"
           data-placeholder="至少6个字符"
           data-type="password"
           data-show-password="true"
           style="width: 100%;"></div>
    </div>
  </div>
  
  <div class="sa-form-item">
    <label class="sa-form-item__label">确认密码</label>
    <div class="sa-form-item__content">
      <div class="sa-input" 
           data-prop="confirmPassword"
           data-placeholder="再次输入密码"
           data-type="password"
           data-show-password="true"
           style="width: 100%;"></div>
    </div>
  </div>
  
  <div class="sa-form-item">
    <label class="sa-form-item__label">邮箱</label>
    <div class="sa-form-item__content">
      <div class="sa-input" 
           data-prop="email"
           data-placeholder="example@email.com"
           data-type="email"
           data-clearable="true"
           style="width: 100%;"></div>
    </div>
  </div>
  
  <div style="margin-top: 20px; display: flex; gap: 10px;">
    <button type="submit" class="sa-button sa-button--primary">注册</button>
    <button type="button" class="sa-button" onclick="resetRegisterForm()">重置</button>
  </div>
</form>

<script>
  SA.init('body');
  
  const registerForm = new SaForm('#register-form', {
    rules: {
      username: [
        { required: true, message: '用户名不能为空' },
        { min: 3, max: 20, message: '用户名长度在 3 到 20 个字符' },
        { pattern: /^[a-zA-Z0-9_]+$/, message: '用户名只能包含字母、数字和下划线' }
      ],
      password: [
        { required: true, message: '密码不能为空' },
        { min: 6, message: '密码长度不能少于 6 个字符' }
      ],
      confirmPassword: [
        { required: true, message: '请确认密码' },
        {
          validator: (rule, value, allValues) => {
            if (value !== allValues.password) {
              return '两次输入的密码不一致';
            }
            return true;
          },
          message: '两次输入的密码不一致'
        }
      ],
      email: [
        { required: true, message: '邮箱不能为空' },
        { type: 'email', message: '请输入正确的邮箱格式' }
      ]
    }
  });
  
  document.getElementById('register-form').addEventListener('submit', async (e) => {
    e.preventDefault();
    
    try {
      const formData = await registerForm.validate();
      console.log('注册数据:', formData);
      alert('注册成功!');
      registerForm.resetFields();
    } catch (errors) {
      console.log('验证失败:', errors);
    }
  });
  
  function resetRegisterForm() {
    registerForm.resetFields();
  }
</script>
加载 SanoUI 组件中...
            
          

场景 2:表单数据回填

从服务器获取数据后,回填到表单中。

html
<form class="sa-form" id="fill-form" style="max-width: 500px;" data-label-position="right" data-label-width="100px">
  <div class="sa-form-item">
    <label class="sa-form-item__label">姓名</label>
    <div class="sa-form-item__content">
      <div class="sa-input" 
           data-prop="name"
           data-placeholder="请输入姓名"
           style="width: 100%;"></div>
    </div>
  </div>
  <div class="sa-form-item">
    <label class="sa-form-item__label">邮箱</label>
    <div class="sa-form-item__content">
      <div class="sa-input" 
           data-prop="email"
           data-placeholder="请输入邮箱"
           data-type="email"
           style="width: 100%;"></div>
    </div>
  </div>
  <div class="sa-form-item">
    <label class="sa-form-item__label">电话</label>
    <div class="sa-form-item__content">
      <div class="sa-input" 
           data-prop="phone"
           data-placeholder="请输入电话"
           data-type="tel"
           style="width: 100%;"></div>
    </div>
  </div>
  
  <div style="margin-top: 20px; display: flex; gap: 10px;">
    <button type="button" class="sa-button sa-button--primary" onclick="loadUserData()">加载用户数据</button>
    <button type="button" class="sa-button" onclick="clearForm()">清空表单</button>
    <button type="button" class="sa-button" onclick="getFormData()">获取表单数据</button>
  </div>
</form>

<script>
  SA.init('body');
  
  const fillForm = new SaForm('#fill-form', {
    rules: {
      name: [{ required: true, message: '姓名不能为空' }],
      email: [
        { required: true, message: '邮箱不能为空' },
        { type: 'email', message: '请输入正确的邮箱格式' }
      ]
    }
  });
  
  function loadUserData() {
    setTimeout(() => {
      const userData = {
        name: '张三',
        email: 'zhangsan@example.com',
        phone: '13800138000'
      };
      fillForm.setFieldsValue(userData);
      alert('数据已加载并回填到表单');
    }, 500);
  }
  
  function clearForm() {
    fillForm.resetFields();
    alert('表单已清空');
  }
  
  function getFormData() {
    const formData = fillForm.getFieldsValue();
    alert('表单数据:\n' + JSON.stringify(formData, null, 2));
  }
</script>
加载 SanoUI 组件中...
            
          

注意事项

  1. 字段注册:表单字段必须通过 data-prop 属性注册,或手动调用 registerField() 方法
  2. 验证时机:默认在字段失焦时验证,可以通过 trigger 配置改变
  3. 异步验证validator 函数支持返回 Promise,实现异步验证
  4. 错误显示:错误消息会自动显示在字段下方,可以通过 showMessage: false 禁用
  5. 表单提交:建议在表单提交时调用 validate() 方法进行完整验证

常见问题

Q: 如何获取表单的所有数据?

A: 使用 getFieldsValue() 方法:

javascript
const formData = form.getFieldsValue();

Q: 如何设置表单字段的值?

A: 使用 setFieldsValue() 方法:

javascript
form.setFieldsValue({
  username: 'admin',
  email: 'admin@example.com'
});

Q: 如何重置表单?

A: 使用 resetFields() 方法:

javascript
form.resetFields(); // 重置所有字段

Q: 如何实现自定义验证?

A: 使用 validator 函数:

javascript
{
  validator: (rule, value, allValues) => {
    if (value !== allValues.password) {
      return '两次输入的密码不一致';
    }
    return true;
  }
}

Released under the MIT License.