Skip to content

Form 表单

由输入框、选择器、单选框、多选框等控件组成,用以收集、校验、提交数据。

名称分类说明类型默认值
inline? 风格是否使用行内表单booleanfalse
labelWidth? 风格标签宽度number | string
labelPosition? 风格标签位置'left' | 'right' | 'top''right'
hideRequiredAsterisk? 风格是否隐藏必填字段的标签旁边的红色星号booleanfalse
requiredAsteriskPosition? 风格星号位置'left' | 'right''left'
FormItemlabelWidth? 风格标签宽度number | string
disabled? 状态是否禁用表单booleanfalse
FormItemdisabled? 状态是否禁用booleanfalse
rules? 行为表单验证规则(支持 Zod schema)FormRules
statusIcon? 行为验证后是否显示状态图标booleanfalse
showMessage? 行为是否显示校验错误信息booleantrue
FormItemrequired? 行为是否必填booleanfalse
FormItemrules? 行为验证规则(支持 Zod schema 或 required 简写)FormItemRule[]
FormItemshowMessage? 行为是否显示校验错误信息booleantrue
FormItemfor? 行为标签的 for 属性,关联到指定的表单控件string
model? 内容表单数据对象Record<string, any>
labelSuffix? 内容标签后缀string
FormItemprop? 内容model 的键名string | string[]
FormItemlabel? 内容标签文本string
FormItemerror? 内容错误信息string
validate? 事件字段验证后触发(prop: string, isValid: boolean, message: string) => void
FormItemdefault? 插槽表单项内容
FormItemlabel? 插槽自定义标签
FormItemerror? 插槽自定义错误信息
validate? 暴露验证整个表单(callback?: FormValidateCallback) => Promise<boolean>
validateField? 暴露验证指定字段(props?: string[], callback?: FormValidateCallback) => Promise<boolean>
resetFields? 暴露重置表单字段(props?: string[]) => void
clearValidate? 暴露清除验证状态(props?: string[]) => void

基础用法

基本的表单数据域控制,包含各种表单项。

<template>
  <px-form :model="form" label-width="80px">
    <px-form-item label="Name">
      <px-input v-model="form.name" placeholder="Enter name" />
    </px-form-item>
    <px-form-item label="Email">
      <px-input v-model="form.email" placeholder="Enter email" />
    </px-form-item>
    <px-form-item label="Active">
      <px-switch v-model="form.active" />
    </px-form-item>
    <px-form-item>
      <px-button type="primary" @click="onSubmit">Submit</px-button>
      <px-button @click="onReset">Reset</px-button>
    </px-form-item>
  </px-form>
</template>

<script setup lang="ts">
import { PxMessage } from 'sakana-element';
import { reactive } from 'vue';

const form = reactive({
  name: '',
  email: '',
  active: false,
});

const onSubmit = () => {
  PxMessage.success('Submit!');
};

const onReset = () => {
  form.name = '';
  form.email = '';
  form.active = false;
};
</script>

表单校验

表单校验使用 Zod 模式验证。每条规则可提供 schema(Zod 类型)或使用 required 简写进行简单的必填检查。

<template>
  <px-form ref="formRef" :model="form" :rules="rules" label-width="80px">
    <px-form-item label="Name" prop="name">
      <px-input v-model="form.name" placeholder="Enter name" />
    </px-form-item>
    <px-form-item label="Email" prop="email">
      <px-input v-model="form.email" placeholder="Enter email" />
    </px-form-item>
    <px-form-item>
      <px-button type="primary" @click="onSubmit">Submit</px-button>
      <px-button @click="onReset">Reset</px-button>
    </px-form-item>
  </px-form>
</template>

<script setup lang="ts">
import { PxMessage } from 'sakana-element';
import { reactive, ref } from 'vue';
import { z } from 'zod';

const formRef = ref();

const form = reactive({
  name: '',
  email: '',
});

const rules = {
  name: [
    { schema: z.string().min(1, 'Please input name'), trigger: 'blur' },
    { schema: z.string().min(2).max(20, 'Length should be 2 to 20'), trigger: 'blur' },
  ],
  email: [
    { schema: z.string().min(1, 'Please input email'), trigger: 'blur' },
    { schema: z.string().email('Please input a valid email'), trigger: 'blur' },
  ],
};

const onSubmit = async () => {
  try {
    await formRef.value.validate();
    PxMessage.success('Submit success!');
  } catch {
    PxMessage.danger('Validation failed');
  }
};

const onReset = () => {
  formRef.value.resetFields();
};
</script>

行内表单

设置 inline 属性可以让表单项水平排列,适用于搜索表单和筛选器。

<template>
  <px-form ref="formRef" :model="form" inline label-width="60px">
    <px-form-item label="Name" prop="name">
      <px-input v-model="form.name" placeholder="Name" />
    </px-form-item>
    <px-form-item label="Email" prop="email">
      <px-input v-model="form.email" placeholder="Email" />
    </px-form-item>
    <px-form-item>
      <px-button type="primary" @click="onSearch">Search</px-button>
    </px-form-item>
  </px-form>
</template>

<script setup lang="ts">
import { PxMessage } from 'sakana-element';
import { reactive, ref } from 'vue';

const formRef = ref();
const form = reactive({
  name: '',
  email: '',
});

const onSearch = () => {
  PxMessage.success('Search submitted!');
};
</script>

标签位置

通过设置 label-position 属性可以改变表单域标签的位置。

<template>
  <div class="demo-form">
    <div class="buttons">
      <px-button @click="labelPosition = 'left'">Left</px-button>
      <px-button @click="labelPosition = 'right'">Right</px-button>
      <px-button @click="labelPosition = 'top'">Top</px-button>
    </div>
    <px-form :model="form" :label-position="labelPosition" label-width="80px">
      <px-form-item label="Name">
        <px-input v-model="form.name" placeholder="Enter name" />
      </px-form-item>
      <px-form-item label="Email">
        <px-input v-model="form.email" placeholder="Enter email" />
      </px-form-item>
      <px-form-item>
        <px-button type="primary" @click="onSubmit">Submit</px-button>
        <px-button @click="onCancel">Cancel</px-button>
      </px-form-item>
    </px-form>
  </div>
</template>

<script setup lang="ts">
import { reactive, ref } from 'vue';

const labelPosition = ref<'left' | 'right' | 'top'>('right');

const form = reactive({
  name: '',
  email: '',
});

function onSubmit() {}

function onCancel() {
  form.name = '';
  form.email = '';
}
</script>

<style scoped>
.demo-form .buttons {
  margin-bottom: 16px;
  display: flex;
  gap: 8px;
}
</style>

状态图标

设置 status-icon 属性可以在验证后显示成功/失败图标。

<template>
  <px-form ref="formRef" :model="form" :rules="rules" status-icon label-width="80px">
    <px-form-item label="Name" prop="name">
      <px-input v-model="form.name" placeholder="Enter name" />
    </px-form-item>
    <px-form-item label="Email" prop="email">
      <px-input v-model="form.email" placeholder="Enter email" />
    </px-form-item>
    <px-form-item>
      <px-button type="primary" @click="onSubmit">Validate</px-button>
      <px-button @click="onReset">Reset</px-button>
    </px-form-item>
  </px-form>
</template>

<script setup lang="ts">
import { reactive, ref } from 'vue';
import { z } from 'zod';

const formRef = ref();
const form = reactive({
  name: '',
  email: '',
});

const rules = {
  name: [{ schema: z.string().min(1, 'Name is required'), trigger: 'blur' }],
  email: [{ schema: z.string().email('Invalid email'), trigger: 'blur' }],
};

const onSubmit = async () => {
  try {
    await formRef.value.validate();
  } catch {
    // validation failed
  }
};

const onReset = () => {
  formRef.value.resetFields();
};
</script>

禁用

在表单上设置 disabled 属性可以禁用所有表单控件。

<template>
  <px-form :model="form" disabled label-width="80px">
    <px-form-item label="Name" prop="name">
      <px-input v-model="form.name" placeholder="Enter name" />
    </px-form-item>
    <px-form-item label="Email" prop="email">
      <px-input v-model="form.email" placeholder="Enter email" />
    </px-form-item>
    <px-form-item label="Active" prop="active">
      <px-switch v-model="form.active" />
    </px-form-item>
    <px-form-item>
      <px-button type="primary" disabled>Submit</px-button>
    </px-form-item>
  </px-form>
</template>

<script setup lang="ts">
import { reactive } from 'vue';

const form = reactive({
  name: 'Sakana',
  email: 'sakana@example.com',
  active: true,
});
</script>