Switch
Switch是对 Vant 开关组件的 Formily 适配,保留原生切换能力,并补上readPretty阅读态。
使用建议
开关字段通常用于布尔状态或双值状态切换,建议直接搭配 FormItem 使用,便于和其他表单组件保持一致的标题、校验与阅读态体验。
基础使用
通过 modelValue 绑定当前开关值。
vue
<script setup lang="ts">
import { createForm } from '@formily/core'
import { Form, FormButtonGroup, FormItem, Submit, Switch } from '@silver-formily/vant'
import { Field } from '@silver-formily/vue'
import { showDemoResult } from '../shared'
const form = createForm({
values: {
enabled: true,
},
})
</script>
<template>
<Form :form="form">
<Field
name="enabled"
title="是否启用"
:decorator="[FormItem]"
:component="[Switch]"
/>
<FormButtonGroup>
<Submit :on-submit="showDemoResult">
查看结果
</Submit>
</FormButtonGroup>
</Form>
</template>自定义开关值
通过 activeValue 和 inactiveValue 将开关值映射为任意业务值。
vue
<script setup lang="ts">
import { createForm } from '@formily/core'
import { Form, FormButtonGroup, FormItem, Submit, Switch } from '@silver-formily/vant'
import { Field } from '@silver-formily/vue'
import { showDemoResult } from '../shared'
const form = createForm({
values: {
status: 'offline',
},
})
</script>
<template>
<Form :form="form">
<Field
name="status"
title="发布状态"
:decorator="[FormItem]"
:component="[Switch, {
activeValue: 'online',
inactiveValue: 'offline',
}]"
/>
<FormButtonGroup>
<Submit :on-submit="showDemoResult">
查看结果
</Submit>
</FormButtonGroup>
</Form>
</template>禁用状态
通过 disabled 禁用开关交互。
vue
<script setup lang="ts">
import { createForm } from '@formily/core'
import { Form, FormButtonGroup, FormItem, Submit, Switch } from '@silver-formily/vant'
import { Field } from '@silver-formily/vue'
import { showDemoResult } from '../shared'
const form = createForm({
values: {
enabled: false,
},
})
</script>
<template>
<Form :form="form">
<Field
name="enabled"
title="禁用开关"
:decorator="[FormItem]"
:component="[Switch, { disabled: true }]"
/>
<FormButtonGroup>
<Submit :on-submit="showDemoResult">
查看结果
</Submit>
</FormButtonGroup>
</Form>
</template>加载状态
在 Formily 场景中,也可以通过字段的 loading 状态驱动开关展示加载态;加载态下同样不可点击。
vue
<script setup lang="ts">
import { createForm } from '@formily/core'
import { Form, FormButtonGroup, FormItem, Submit, Switch } from '@silver-formily/vant'
import { Field } from '@silver-formily/vue'
import { showDemoResult } from '../shared'
const form = createForm({
values: {
syncing: true,
},
})
</script>
<template>
<Form :form="form">
<Field
name="syncing"
title="加载状态"
loading
:decorator="[FormItem]"
:component="[Switch]"
/>
<FormButtonGroup>
<Submit :on-submit="showDemoResult">
查看结果
</Submit>
</FormButtonGroup>
</Form>
</template>自定义大小
通过 size 调整开关尺寸。
vue
<script setup lang="ts">
import { createForm } from '@formily/core'
import { Form, FormButtonGroup, FormItem, Submit, Switch } from '@silver-formily/vant'
import { Field } from '@silver-formily/vue'
import { showDemoResult } from '../shared'
const form = createForm({
values: {
compact: true,
},
})
</script>
<template>
<Form :form="form">
<Field
name="compact"
title="自定义大小"
:decorator="[FormItem]"
:component="[Switch, { size: '22px' }]"
/>
<FormButtonGroup>
<Submit :on-submit="showDemoResult">
查看结果
</Submit>
</FormButtonGroup>
</Form>
</template>自定义颜色
通过 activeColor 和 inactiveColor 调整开关的开关状态颜色。
vue
<script setup lang="ts">
import { createForm } from '@formily/core'
import { Form, FormButtonGroup, FormItem, Submit, Switch } from '@silver-formily/vant'
import { Field } from '@silver-formily/vue'
import { showDemoResult } from '../shared'
const form = createForm({
values: {
branded: true,
},
})
</script>
<template>
<Form :form="form">
<Field
name="branded"
title="自定义颜色"
:decorator="[FormItem]"
:component="[Switch, {
activeColor: '#ee0a24',
inactiveColor: '#dcdee0',
}]"
/>
<FormButtonGroup>
<Submit :on-submit="showDemoResult">
查看结果
</Submit>
</FormButtonGroup>
</Form>
</template>自定义按钮
通过 node 插槽自定义按钮内容。
vue
<script setup lang="ts">
import { createForm } from '@formily/core'
import { Form, FormButtonGroup, FormItem, Submit, Switch } from '@silver-formily/vant'
import { Field } from '@silver-formily/vue'
import { Icon } from 'vant'
import { showDemoResult } from '../shared'
const form = createForm({
values: {
approved: true,
},
})
</script>
<template>
<Form :form="form">
<Field
name="approved"
title="自定义按钮"
:decorator="[FormItem]"
:component="[Switch]"
>
<template #node="{ field }">
<div class="switch-node-icon">
<Icon :name="field?.value ? 'success' : 'cross'" />
</div>
</template>
</Field>
<FormButtonGroup>
<Submit :on-submit="showDemoResult">
查看结果
</Submit>
</FormButtonGroup>
</Form>
</template>
<style scoped>
.switch-node-icon {
display: flex;
width: 100%;
justify-content: center;
font-size: 18px;
}
.switch-node-icon :deep(.van-icon) {
line-height: 32px;
}
.switch-node-icon :deep(.van-icon-success) {
color: var(--van-blue);
}
.switch-node-icon :deep(.van-icon-cross) {
color: var(--van-gray-5);
}
</style>异步控制
如果需要先确认、再真正写回字段值,可以直接使用 beforeChange。它会在切换前触发;当返回 false、返回值解析为 false,或 Promise 被 reject 时,都会阻止这次切换。异步 Promise 等待期间,组件会自动展示 loading,省掉手动维护一套临时状态。
vue
<script setup lang="ts">
import { createForm } from '@formily/core'
import { Form, FormButtonGroup, FormItem, Submit, Switch } from '@silver-formily/vant'
import { Field } from '@silver-formily/vue'
import { showDemoResult } from '../shared'
const form = createForm({
values: {
asyncEnabled: true,
},
})
function sleep(duration: number) {
return new Promise(resolve => setTimeout(resolve, duration))
}
async function handleBeforeChange(nextValue: boolean) {
const actionText = nextValue ? '开启' : '关闭'
const confirmed = await Prompts.confirm(`确认将“异步开关”切换为${actionText}吗?`)
if (!confirmed) {
return false
}
await sleep(600)
return true
}
</script>
<template>
<Form :form="form">
<Field
name="asyncEnabled"
title="异步开关"
:decorator="[FormItem]"
:component="[Switch, {
beforeChange: handleBeforeChange,
}]"
/>
<FormButtonGroup>
<Submit :on-submit="showDemoResult">
查看结果
</Submit>
</FormButtonGroup>
</Form>
</template>搭配单元格使用
可以像官方示例一样将开关放进 Cell 的右侧区域使用。
vue
<script setup lang="ts">
import { createForm } from '@formily/core'
import { Form, FormButtonGroup, Submit, Switch } from '@silver-formily/vant'
import { Field } from '@silver-formily/vue'
import { Cell, CellGroup } from 'vant'
import { showDemoResult } from '../shared'
const form = createForm({
values: {
notifyBySms: true,
},
})
</script>
<template>
<Form :form="form">
<CellGroup inset>
<Cell
center
title="短信通知"
label="打开后将在提交结果外额外发送短信提醒。"
>
<template #right-icon>
<Field
name="notifyBySms"
:component="[Switch]"
/>
</template>
</Cell>
</CellGroup>
<FormButtonGroup>
<Submit :on-submit="showDemoResult">
查看结果
</Submit>
</FormButtonGroup>
</Form>
</template>API
使用约定
- Formily 场景统一使用
modelValue作为字段值,默认是boolean readPretty模式下会自动切换到PreviewText.Switch,只有字段值精确匹配activeValue/inactiveValue时才显示开关,否则显示占位符,避免把非法值误显示为“关闭”beforeChange会在真正触发update:modelValue/change之前执行,适合做确认弹窗、权限校验、异步请求前置判断- 未单独列出的 Vant
Switch官方属性和事件会继续透传
扩展属性
| 属性名 | 类型 | 描述 | 默认值 |
|---|---|---|---|
beforeChange | Function | 切换前钩子。显式返回 false、Promise resolve 为 false 或 Promise reject 时会阻止切换 | - |
官方透传属性
以下属性会直接透传给 Vant Switch:
| 属性名 | 类型 | 描述 | 默认值 |
|---|---|---|---|
size | number | string | 开关尺寸 | 官方默认值 |
loading | boolean | 是否显示加载中 | 官方默认值 |
disabled | boolean | 是否禁用 | 官方默认值 |
activeColor | string | 打开时的背景色 | 官方默认值 |
inactiveColor | string | 关闭时的背景色 | 官方默认值 |
activeValue | unknown | 打开时对应的值 | true |
inactiveValue | unknown | 关闭时对应的值 | false |
Events
| 事件名 | 描述 | 回调参数 |
|---|---|---|
update:modelValue | 开关值变化时触发 | Function |
change | 开关值确认变更后触发 | Function |
Slots
| 插槽名 | 描述 | 插槽参数 |
|---|---|---|
node | 自定义按钮内容 | - |
background | 自定义开关背景内容 | - |
参考
基础属性主要参考 Vant Switch 官方文档(正式站),beforeChange 的命名和“切换前拦截”语义参考了 Element Plus Switch。