naive-ui-form文档
更新日志
v3.1.0
- 修改富文本为
naive-ui-editor
简介
INFO
naive-ui-form
是基于naive-ui
封装的表单组件。一个配置,生成一个表单。支持typescript
。
naive-ui-form
相比于使用n-form
原生表单有如下优势:
- 无需手动布局,组件内部使用
n-grid
自动布局,只需传入props参数即可,灵活配置。 - 无需手写校验
rules
,大部分场景下只需要传一个required:true
就可以了。 - 支持
动态表单
,减少开发时间和复杂度。 - 内置了
文件上传(支持图片裁剪)
、富文本
等插件,方便开发 - 完整的
ts
类型提示
下面是naive-ui-form
的一个完整表单的示例:
<template>
<BasicForm @register="register"></BasicForm>
</template>
<script setup lang="tsx">
import { BasicForm, useForm, type Recordable } from 'naive-ui-form'
const [register] = useForm({
schemas: [
{
field: 'name',
type: 'input',
label: '姓名',
required: true,
labelPlacement: 'left',
defaultValue: '张三',
componentProps: {
onUpdateValue(value: string) {
console.log(value)
}
},
style: {
width: '200px'
}
},
{
field: 'sex',
type: 'radio',
label: '性别',
required: true,
componentProps: {
options: [
{
label: '男',
value: 'male'
},
{
label: '女',
value: 'female'
}
]
}
},
{
field: 'hobbies',
type: 'checkbox',
label: '爱好',
required: true,
requiredType: 'array',
componentProps: {
options: [
{
label: '吃饭',
value: 'eat'
},
{
label: '睡觉',
value: 'sleep'
},
{
label: '打豆豆',
value: 'play'
}
]
}
},
{
field: 'birthday',
type: 'date-picker',
label: '生日'
},
{
field: 'family',
label: '家庭成员',
type: 'dynamic',
dynamicOptions: [
{
field: 'name',
label: '姓名',
type: 'input',
required: true
},
{
field: 'age',
label: '年龄',
type: 'input-number',
rules: {
required: true,
message: ''
}
},
{
field: 'sex',
label: '性别',
type: 'radio',
componentProps: {
options: [
{
label: '男',
value: 'male'
},
{
label: '女',
value: 'female'
}
]
}
}
]
}
]
})
</script>
<style scoped></style>
安装
pnpm add naive-ui-form
也可以使用npm
、yarn
等安装。
注意
必须安装了以下依赖才能使用naive-ui-form
{
"vue": ">=3.2.0",
"naive-ui": ">=2.34.0",
"@vicons/ionicons5": ">=0.12.0"
}
确保naive-ui
已经配置到项目中:
<template>
<NConfigProvider :locale="zhCN" :date-locale="dateZhCN">
<NMessageProvider>
<router-view></router-view>
</NMessageProvider>
</NConfigProvider>
</template>
<script setup lang="ts">
import { NConfigProvider, zhCN, dateZhCN, NMessageProvider } from 'naive-ui'
</script>
<style scoped></style>
提示
- 如果表单中使用了
type: 'upload'
,则需要安装naive-ui-upload,并注册该组件。 - 如果表单中使用了
type: 'editor'
,则需要安装naive-ui-editor,并注册该组件。
基本使用
局部导入
<template>
<BasicForm></BasicForm>
</template>
<script setup lang="ts">
import { BasicForm } from 'naive-ui-form'
</script>
全局导入
import { createApp } from 'vue'
import NaiveUiForm from 'naive-ui-form'
const app = createApp(App)
app.use(NaiveUiForm)
props传值方式
传递props
有两种方法:
使用经典传值方式:
vue<template> <BasicForm :schemas="schemas"></BasicForm> </template>
使用
useForm
:vue<template> <BasicForm @register="register"></BasicForm> </template> <script setup lang="ts"> import { BasicForm, useForm } from 'naive-ui-form' const [register] = useForm({ schemas: [] }) </script>
提示
如果props
和useForm()
传值有冲突,useForm
会覆盖props
。
注册事件
naive-ui-form
注册了以下事件:
- register: 使用
useForm
注册的时候用到 - submit:表单提交出发(只有表单校验成功后才会触发)
- reset:表单重置的时候触发
useForm
naive-ui-form
为了方便对表单的操作,封装了一些方法。
注意
在使用这些方法之前,一定要先注册register
到naive-ui-form
上
<template>
<BasicForm @register="register"></BasicForm>
</template>
<script setup lang="ts">
import { BasicForm, useForm } from 'naive-ui-form'
const [register, { submit }] = useForm()
</script>
interface FormInstance {
// 重置表单
reset(): void
// 提交表单,返回Promise<Recordable>,校验通过后返回表单的值,校验失败后返回校验的Error
submit(): Promise<Recordable>
// 校验表单,返回Primise,校验通过后进入resolve状态
validate(nameList?: string[]): Promise<any>
// 清空校验
clearValidate(): void
// 获取表单的值
getValue(): Recordable
// 获取表单某个项的值
getFieldValue(field: string): any
// 设置表单的值
setValue(value: Recordable): void
// 动态设置表单的Props
setProps(props: Props): void
// 手动设置表单提交按钮的加载状态
setLoading(loading: boolean): void
}
<template>
<div>
<BasicForm @register="register" :show-action-btns="false"></BasicForm>
<NSpace>
<NButton type="primary" @click="handleSubmit">提交</NButton>
<NButton type="primary" @click="handleReset">重置</NButton>
<NButton type="primary" @click="handleVerify">校验</NButton>
<NButton type="primary" @click="handleClearVerify">清空校验</NButton>
<NButton type="primary" @click="handleGetValue">获取表单值</NButton>
<NButton type="primary" @click="handleGetFieldValue">获取某个值</NButton>
<NButton type="primary" @click="handleSetValue">手动赋值</NButton>
</NSpace>
</div>
</template>
<script setup lang="tsx">
import { NSpace, NButton } from 'naive-ui'
import { BasicForm, useForm, type Recordable } from 'naive-ui-form'
const [
register,
{ submit, reset, validate, clearValidate, getValue, getFieldValue, setValue, setProps }
] = useForm({
schemas: [
{
field: 'name',
type: 'input',
label: '姓名',
required: true,
labelPlacement: 'left',
defaultValue: '张三',
componentProps: {
onUpdateValue(value: string) {
console.log(value)
}
},
style: {
width: '200px'
}
},
{
field: 'sex',
type: 'radio',
label: '性别',
required: true,
componentProps: {
options: [
{
label: '男',
value: 'male'
},
{
label: '女',
value: 'female'
}
]
}
},
{
field: 'hobbies',
type: 'checkbox',
label: '爱好',
required: true,
requiredType: 'array',
componentProps: {
options: [
{
label: '吃饭',
value: 'eat'
},
{
label: '睡觉',
value: 'sleep'
},
{
label: '打豆豆',
value: 'play'
}
]
}
},
{
field: 'birthday',
type: 'date-picker',
label: '生日'
},
{
field: 'school',
type: 'custom',
label: '学校',
required: true,
render(formValue: Recordable, field: string) {
return <input v-model={formValue[field]} style={{ border: '1px solid #ccc' }} />
}
}
]
})
function handleSubmit() {
submit()
.then((res: Recordable) => {
console.log(`表单校验成功`)
console.log(res)
})
.catch((err) => {
console.log('表单校验失败失败', err)
})
}
function handleReset() {
reset()
console.log('表单已重置')
}
function handleVerify() {
validate()
.then(() => console.log('校验通过'))
.catch(() => console.log('校验失败'))
}
function handleClearVerify() {
clearValidate()
console.log('校验已清空')
}
function handleGetValue() {
console.log(getValue())
}
function handleGetFieldValue() {
console.log(getFieldValue('name'))
}
function handleSetValue() {
setValue({
name: '李四',
school: '北京大学',
sex: 'male',
hobbies: ['eat', 'sleep'],
birthday: '2000-01-01'
})
}
</script>
<style scoped></style>
组件api
如果不想使用useForm,也可以直接通过naive-form-ui
组件自身调用上面的方法:
<template>
<div>
<BasicForm ref="formRef" :schemas="schemas" :show-action-btns="false"></BasicForm>
<NSpace>
<NButton type="primary" @click="handleSubmit">提交</NButton>
<NButton type="primary" @click="handleReset">重置</NButton>
</NSpace>
</div>
</template>
<script setup lang="ts">
import { NSpace, NButton } from 'naive-ui'
import { BasicForm, type FormSchema, type FormInstance } from 'naive-ui-form'
import { ref } from 'vue'
const formRef = ref<FormInstance | null>(null)
const schemas: FormSchema[] = [
{
field: 'name',
label: '姓名',
type: 'input',
required: true
}
]
function handleSubmit() {
formRef.value?.submit()
}
function handleReset() {
formRef.value?.reset()
}
</script>
<style scoped></style>
props说明
字段 | 类型 | 描述 | 必传 | 默认值 |
---|---|---|---|---|
schemas | FormSchema[] | 表单配置,详见schemas | 是 | - |
grid | Object | <n-grid> 的props,详见n-grid | 否 | - |
showActionBtns | Boolean | 是否展示表单的操作按钮(提交、重置、展开),优先级最高 | 否 | true |
showSubmitBtn | Boolean | 是否展示提交按钮 | 否 | true |
submitBtnText | String | 提交按钮文字 | 否 | "提交" |
showResetBtn | Boolean | 是否展示重置按钮 | 否 | true |
resetBtnText | String | 重置按钮文字 | 否 | "重置" |
showExpandBtn | Boolean | 是否展示展开/折叠按钮 | 否 | true |
expandBtnOffText | String | ”折叠“状态时候的文字 | 否 | ”展开“ |
expandBtnOnText | String | ”展开“状态时候的文字 | 否 | ”收起“ |
defaultExpand | Boolean | 是否默认折叠 | 否 | false |
defaultShowExpandColumn | Number | 默认展开的行数 | 否 | 1 |
提示
支持传入n-form的props。组件内部重写了部分props,即使你手动传入也是无效的,如model
、rules
schemas
schemas
是naive-ui-form
中重要的配置,如果你使用了typescript
,你可以从naive-ui-form
中导入FormSchema
类型
<template>
<BasicForm @register="register"></BasicForm>
</template>
<script setup lang="ts">
import { BasicForm, useForm, type FormSchema } from 'naive-ui-form'
const schemas: FormSchema[] = []
const [register] = useForm({
schemas
})
</script>
FormSchema字段说明
字段 | 类型 | 描述 | 是否必填 |
---|---|---|---|
tip | string 或() => VNode | 填写自此字段会在表单下面生成一句提示信息 | 否 |
field | string | 整个表单的值是一个对象,该字段就是描述需要v-model到该字段上,如该字段设置为"name",那么表单的值就是 | 是 |
type | string | 见type字段说明 | 是 |
defaultValue | any | 该项的默认值 | 否 |
componentProps | Object | naive-ui 原生表单项(如n-input 、n-select 等)的props,通过该字段传入 | 否 |
required | boolean | 该项是否必填,如果设置为true 组件内部会自动校验必填,优先级最高 | 否 |
requiredType | string | required 为true 时校验的特殊类型,如array 、number | 否 |
requiredMessage | string | required 为true 校验未通过的信息 | 否 |
requiredTrigger | string 或string[] | required 为true 校验的出发方式 | 否 |
rules | FormItemRule 或FormItemRule[] | required 为true 时无效,自定义表单校验,同n-form-item的rule 属性 | 否 |
style | Object | 设置n-form-item 的style | 否 |
vif | (value:Recordable) => boolean | 动态显示该表单,需要返回一个布尔值,value 是表单的值 | 否 |
slot | string | 当type字段为slot 的时候必传,插槽名称 | 否 |
dynamicOptions | FormSchema[] | 动态表单的配置,当type字段为dynamic 的时候必传 | 否 |
groupName | string | 表单分组标识,该选项设置会了该表单项前面添加一个分组标识 | 否 |
提示
FormSchema
也接收NFormItemGi的props。
type字段说明
type
字段映射了naive-ui
的表单组件,映射关系如下:
字段 | 映射的组件 |
---|---|
auto-complete | NAutoComplete |
cascader | NCascader |
color-picker | NColorPicker |
checkbox | NCheckboxGroup |
date-picker | NDatePicker |
dynamic-input | NDynamicInput |
dynamic-tags | NDynamicTags |
input | NInput |
input-number | NInputNumber |
mention | NMention |
radio-single | NRadio |
radio | NRadioGroup |
rate | NRate |
select | NSelect |
slider | NSlider |
switch | NSwitch |
time-picker | NTimePicker |
transfer | NTransfer |
tree-select | NTreeSelect |
slot | 见插槽 |
dynamic | 见动态表单 |
upload | 见naive-ui-upload |
editor | 见naive-ui-editor |
text | NText,用于数据展示 |
提示
一些特殊的type
说明:
radio
: 需要在componentProps
传入options
字段,如果是异步数据可以定义为ref
响应数据。ts{ field: 'sex', type: 'radio', label: '性别', required: true, componentProps: { options: [ { label: '男', value: 'male' }, { label: '女', value: 'female' } ] } }
checkbox
:同上radio
date-picker
: 默认的格式为yyyy-MM-dd
,格式请参考这里修改方式如下:ts{ field: 'birthday', type: 'date-picker', label: '生日', componentProps: { valueFormat: 'xxxxx' } }
time-picker
: 默认的格式为HH:mm:ss
,修改同上。
插槽
如果内置的type不满足时,可以使用插槽。type
设置为slot
, 再加一个slot
名称,示例如下:
<template>
<BasicForm @register="register">
<template #username="{ formValue, field }">
<input
v-model="formValue[field]"
type="text"
placeholder="这是插槽"
style="border: 1px solid #ccc"
/>
</template>
</BasicForm>
</template>
<script setup lang="ts">
import { BasicForm, useForm } from 'naive-ui-form'
const [register] = useForm({
schemas: [
{
field: 'username',
type: 'slot',
label: '用户名',
required: true,
slot: 'username'
}
]
})
</script>
<style scoped></style>
动态表单
提示
在使用动态表单时候,由于naive-ui
的n-form
组件设置了label-width: "auto"
后,导致子组件无法自适应宽度,所以需要设置naive-ui-form
的label-width
不为auto
,否则会出现宽度不协调的问题。
动态表单
需要将type
设置为dynamic
,再新增一个dynamicOptions
配置,示例如下:
<template>
<BasicForm @register="register"></BasicForm>
</template>
<script setup lang="ts">
import { BasicForm, useForm } from 'naive-ui-form'
const [register] = useForm({
labelWidth: '200px',
schemas: [
{
field: 'family',
label: '家庭成员',
type: 'dynamic',
dynamicOptions: [
{
field: 'name',
label: '姓名',
type: 'input',
required: true
},
{
field: 'age',
label: '年龄',
type: 'input-number',
required: true
}
]
}
]
})
</script>
<style scoped></style>
ModalForm
ModalForm
是BasicForm
的封装,主要是为了方便在弹窗中使用。可以直接传入BasicForm
、n-modal、dialog支持的props
。ModalForm
会在校验通过后出发submit
事件,参数就是表单的值。点击取消按钮
时还会触发cancel
事件。
<template>
<div>
<NButton type="primary" @click="showModal = true">显示弹窗</NButton>
<ModalForm
v-model:show="showModal"
:schemas="schemas"
title="新增用户"
:loading="loading"
@submit="handleSubmit"
></ModalForm>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { NButton } from 'naive-ui'
import { ModalForm, type FormSchema, type Recordable } from 'naive-ui-form'
const showModal = ref(false)
const schemas: FormSchema[] = [
{
field: 'name',
label: '姓名',
type: 'input',
required: true
},
{
field: 'age',
label: '年龄',
type: 'input-number',
required: true,
requiredType: 'number'
}
]
const loading = ref(false)
function handleSubmit(values: Recordable) {
console.log(values)
loading.value = true
setTimeout(() => {
loading.value = false
showModal.value = false
}, 2000)
}
</script>
<style scoped></style>
有时候需要获取整个表单值去做一些额外的事情,如表单校验。ModalForm
组件暴露了getValue
、setValue
、getFieldValue
方法:
<template>
<ModalForm
v-model:show="showModal"
title="新增"
ref="modalRef"
:schemas="schemas"
style="width: 800px"
@submit="handleModalSubmit"
></ModalForm>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { type FormSchema, type ModalFormInstance } from 'naive-ui-form'
const showModal = ref(true)
const schemas: FormSchema[] = [
{
field: 'name',
type: 'input',
label: '姓名',
required: true,
labelPlacement: 'left',
defaultValue: '张三',
componentProps: {
onUpdateValue(value: string) {
console.log(value)
}
},
style: {
width: '200px'
}
}
]
const modalRef = ref<ModalFormInstance | null>(null)
setTimeout(() => {
console.log(modalRef.value?.getValue())
}, 3000)
</script>
<style scoped></style>