组件值格式转换
为表单组件绑定自定义转换器,用于处理特殊的数据格式或转换逻辑。通过转换器可以实现数据的双向转换:将后端数据转换为表单显示格式(正向),以及将表单数据转换为后端所需格式(逆向)。
转换器概述
转换器提供了两个转换方法:
toFormValue: 正向转换,将后端数据转换为表单组件显示的值toValue: 逆向转换,将表单组件的值转换为提交给后端的数据格式
使用场景
转换器适用于以下场景:
- 数据格式转换(如字符串与数组互转)
- 数据清理(如去除空格、格式化)
- 数据类型转换(如字符串与数字互转)
- 复杂数据结构处理
快速开始
1. 挂载转换器
在 main.js 中全局挂载转换器
import {formCreate} from '/path/to/fcDesignerPro/dist/index.es.js'
formCreate.parser({
name: 'input',
merge: true,
toFormValue(val) {
return (val || '').trim()
},
toValue(val) {
return (val || '').trim()
},
})2. 使用转换器
转换器会在以下场景自动触发:
- 表单回显时:调用
toFormValue将后端数据转换为表单显示值 - 表单提交时:调用
toValue将表单值转换为提交数据
<template>
<form-create v-model="formData" :rule="rule" v-model:api="fApi" @submit="handleSubmit"></form-create>
</template>
<script setup>
import {ref} from 'vue';
import {formCreate} from '/path/to/fcDesignerPro/dist/index.es.js'
const formData = ref({});
const fApi = ref(null);
const rule = ref([
{
type: 'input',
field: 'username',
title: '用户名',
}
]);
function handleSubmit(formData) {
// 此时 formData.username 已经通过 toValue 处理,去除了前后空格
console.log('提交数据:', formData);
}
</script>完整示例
示例 1: 去除输入框前后空格
自动去除 input 组件输入值的前后空格,确保数据整洁。
import {formCreate} from '/path/to/fcDesignerPro/dist/index.es.js'
formCreate.parser({
name: 'input',
merge: true,
// 正向转换:从后端数据转换为表单显示值
toFormValue(val) {
// 如果值为 null 或 undefined,返回空字符串
if (val == null) {
return '';
}
// 去除前后空格
return String(val).trim();
},
// 逆向转换:从表单值转换为提交数据
toValue(val) {
// 提交时也去除前后空格
if (val == null) {
return '';
}
return String(val).trim();
},
});使用场景:
<template>
<form-create v-model="formData" :rule="rule" v-model:api="fApi"></form-create>
</template>
<script setup>
import {ref, onMounted} from 'vue';
const formData = ref({});
const fApi = ref(null);
const rule = ref([
{
type: 'input',
field: 'username',
title: '用户名',
}
]);
// 模拟从后端加载数据(包含前后空格)
formData.value = {
username: ' admin ' // 包含前后空格
};
// 表单回显时,toFormValue 会自动去除空格,显示为 'admin'
function handleSubmit(data) {
// 用户输入 ' test ',提交时 toValue 会自动转换为 'test'
console.log(data.username); // 输出: 'test'
}
</script>示例 2: Checkbox 值转换为逗号分隔字符串
将 checkbox 组件的数组值转换为逗号分隔的字符串,便于后端存储和处理。
import {formCreate} from '/path/to/fcDesignerPro/dist/index.es.js'
formCreate.parser({
name: 'checkbox',
merge: true,
// 正向转换:从后端字符串转换为表单数组
toFormValue(val) {
if (!val) {
return [];
}
// 如果是字符串,按逗号分割转换为数组
if (typeof val === 'string') {
return val.split(',').map(item => item.trim()).filter(item => item);
}
// 如果已经是数组,直接返回
if (Array.isArray(val)) {
return val;
}
return [];
},
// 逆向转换:从表单数组转换为提交字符串
toValue(val) {
if (!val || !Array.isArray(val)) {
return '';
}
// 将数组转换为逗号分隔的字符串
return val.filter(item => item).join(',');
},
});使用场景:
<template>
<form-create v-model="formData" :rule="rule" v-model:api="fApi" @submit="handleSubmit"></form-create>
</template>
<script setup>
import {ref, onMounted} from 'vue';
const formData = ref({});
const fApi = ref(null);
const rule = ref([
{
type: 'checkbox',
field: 'hobbies',
title: '兴趣爱好',
options: [
{label: '阅读', value: 'reading'},
{label: '运动', value: 'sports'},
{label: '音乐', value: 'music'},
{label: '旅行', value: 'travel'},
]
}
]);
// 模拟从后端加载数据(字符串格式)
formData.value = {
hobbies: 'reading,sports,music' // 后端存储为字符串
};
// 表单回显时,toFormValue 会自动转换为数组 ['reading', 'sports', 'music']
function handleSubmit(data) {
// 用户选择了 ['reading', 'travel'],提交时 toValue 会自动转换为 'reading,travel'
console.log(data.hobbies); // 输出: 'reading,travel'
// 可以直接提交给后端,无需额外处理
}
</script>示例 3: 数字格式化
将字符串数字转换为数字类型,或保持数字格式。适用于需要将输入框的字符串值转换为数字类型提交给后端的场景。
import {formCreate} from '/path/to/fcDesignerPro/dist/index.es.js'
formCreate.parser({
name: 'input',
merge: true,
// 正向转换:确保显示为字符串(表单组件需要)
toFormValue(val) {
if (val == null) {
return '';
}
// 如果是数字,转换为字符串显示
return String(val);
},
// 逆向转换:转换为数字类型提交
toValue(val) {
if (val === '' || val == null) {
return null;
}
// 转换为数字
const num = Number(val);
// 如果转换失败,返回原值
return isNaN(num) ? val : num;
},
});使用场景:
<template>
<form-create v-model="formData" :rule="rule" v-model:api="fApi" @submit="handleSubmit"></form-create>
</template>
<script setup>
import {ref} from 'vue';
const formData = ref({});
const fApi = ref(null);
const rule = ref([
{
type: 'input',
field: 'price',
title: '商品价格',
props: {
type: 'number',
placeholder: '请输入价格'
}
},
{
type: 'input',
field: 'quantity',
title: '库存数量',
props: {
type: 'number',
placeholder: '请输入数量'
}
}
]);
// 模拟从后端加载数据(数字类型)
formData.value = {
price: 99.99, // 后端返回数字类型
quantity: 100 // 后端返回数字类型
};
// 表单回显时,toFormValue 会自动转换为字符串 '99.99' 和 '100' 显示
function handleSubmit(data) {
// 用户输入 '199.50' 和 '50',提交时 toValue 会自动转换为数字类型
console.log(data.price); // 输出: 199.5 (数字类型)
console.log(data.quantity); // 输出: 50 (数字类型)
console.log(typeof data.price); // 输出: 'number'
// 可以直接进行数学运算,无需手动转换
const total = data.price * data.quantity;
console.log('总价:', total); // 输出: 9975
}
</script>示例 4: 日期格式化
处理日期格式的转换,将时间戳或日期字符串转换为统一的显示格式。适用于后端存储时间戳,但表单组件需要日期对象的场景。
import {formCreate} from '/path/to/fcDesignerPro/dist/index.es.js'
formCreate.parser({
name: 'datePicker',
merge: true,
// 正向转换:将后端日期格式转换为组件需要的格式
toFormValue(val) {
if (!val) {
return null;
}
// 如果是时间戳,转换为日期对象
if (typeof val === 'number') {
return new Date(val);
}
// 如果是字符串,转换为日期对象
if (typeof val === 'string') {
return new Date(val);
}
return val;
},
// 逆向转换:将日期对象转换为时间戳提交
toValue(val) {
if (!val) {
return null;
}
// 如果是日期对象,转换为时间戳
if (val instanceof Date) {
return val.getTime();
}
return val;
},
});使用场景:
<template>
<form-create v-model="formData" :rule="rule" v-model:api="fApi" @submit="handleSubmit"></form-create>
</template>
<script setup>
import {ref} from 'vue';
const formData = ref({});
const fApi = ref(null);
const rule = ref([
{
type: 'datePicker',
field: 'birthday',
title: '出生日期',
props: {
type: 'date',
placeholder: '请选择日期'
}
},
{
type: 'datePicker',
field: 'startTime',
title: '开始时间',
props: {
type: 'datetime',
placeholder: '请选择日期时间'
}
}
]);
// 模拟从后端加载数据(时间戳格式)
formData.value = {
birthday: 631123200000, // 后端返回时间戳:1990-01-01
startTime: 1609459200000 // 后端返回时间戳:2021-01-01 00:00:00
};
// 表单回显时,toFormValue 会自动转换为日期对象显示
function handleSubmit(data) {
// 用户选择了日期,提交时 toValue 会自动转换为时间戳
console.log(data.birthday); // 输出: 631123200000 (时间戳)
console.log(data.startTime); // 输出: 1609459200000 (时间戳)
console.log(typeof data.birthday); // 输出: 'number'
// 可以直接提交给后端,无需手动转换
// 后端接口通常接收时间戳格式,便于存储和计算
}
</script>示例 5: 使用上下文信息
转换器函数可以接收上下文参数,用于更复杂的转换逻辑。适用于需要根据组件配置动态决定转换方式的场景。
import {formCreate} from '/path/to/fcDesignerPro/dist/index.es.js'
formCreate.parser({
name: 'select',
merge: true,
// 正向转换:使用上下文信息
toFormValue(val, ctx) {
// ctx 包含当前规则、表单数据等信息
const {prop} = ctx;
// 根据规则配置决定转换方式
if (prop.props?.multiple) {
// 多选模式:字符串转数组
if (typeof val === 'string') {
return val.split(',').filter(item => item);
}
return Array.isArray(val) ? val : [];
} else {
// 单选模式:直接返回
return val || '';
}
},
// 逆向转换:使用上下文信息
toValue(val, ctx) {
const {prop} = ctx;
if (prop.props?.multiple) {
// 多选模式:数组转字符串
return Array.isArray(val) ? val.join(',') : '';
} else {
// 单选模式:直接返回
return val || '';
}
},
});使用场景:
<template>
<form-create v-model="formData" :rule="rule" v-model:api="fApi" @submit="handleSubmit"></form-create>
</template>
<script setup>
import {ref} from 'vue';
const formData = ref({});
const fApi = ref(null);
const rule = ref([
{
type: 'select',
field: 'category',
title: '商品分类',
props: {
multiple: false, // 单选模式
placeholder: '请选择分类'
},
options: [
{label: '电子产品', value: 'electronics'},
{label: '服装', value: 'clothing'},
{label: '食品', value: 'food'}
]
},
{
type: 'select',
field: 'tags',
title: '商品标签',
props: {
multiple: true, // 多选模式
placeholder: '请选择标签'
},
options: [
{label: '热销', value: 'hot'},
{label: '新品', value: 'new'},
{label: '推荐', value: 'recommend'}
]
}
]);
// 模拟从后端加载数据
formData.value = {
category: 'electronics', // 单选:后端返回字符串
tags: 'hot,new,recommend' // 多选:后端返回逗号分隔字符串
};
// 表单回显时:
// - category 单选:直接显示 'electronics'
// - tags 多选:toFormValue 自动转换为数组 ['hot', 'new', 'recommend']
function handleSubmit(data) {
// 用户操作后提交:
// - category 单选:直接返回字符串 'clothing'
// - tags 多选:toValue 自动转换为字符串 'hot,new'
console.log(data.category); // 输出: 'clothing' (字符串)
console.log(data.tags); // 输出: 'hot,new' (字符串,多选自动转换)
// 同一个转换器根据组件配置自动适配不同的转换逻辑
// 无需为单选和多选分别注册不同的转换器
}
</script>转换器方法说明
toFormValue
功能:将后端数据转换为表单组件显示的值
调用时机:
- 表单初始化时
- 调用
fApi.reload()方法时 - 设置表单数据时
参数:
value: 后端数据的值ctx: 上下文对象,包含以下属性:prop: 当前组件的规则配置$api: 表单 API 实例
返回值:转换后的表单显示值
toValue
功能:将表单组件的值转换为提交给后端的数据格式
调用时机:
- 表单提交时
- 调用
fApi.submit()方法时 - 获取表单数据时
参数:
value: 表单组件的当前值ctx: 上下文对象,包含以下属性:prop: 当前组件的规则配置$api: 表单 API 实例
返回值:转换后的提交数据
注意事项
转换器作用域:转换器是按组件名称(
name)绑定的,同一个组件名称只能注册一个转换器,后注册的会覆盖先注册的。性能考虑:转换器会在每次数据转换时调用,避免在转换器中执行耗时操作。
数据一致性:确保
toFormValue和toValue是互逆的,即toValue(toFormValue(val))应该等于原始值(或等价值)。空值处理:建议在转换器中妥善处理
null、undefined和空字符串等边界情况。类型安全:注意数据类型的转换,避免类型不匹配导致的错误。
数据结构
type Parser = (name: string, parser: ParserConfig) => void;
interface ParserConfig {
// 是否合并内置解析规则, 内置组件请保持 true
merge?: true;
// 正向转换:将后端数据转换为表单显示值
toFormValue?: (value: any, ctx: ParserContext) => any;
// 逆向转换:将表单值转换为提交数据
toValue?: (value: any, ctx: ParserContext) => any;
}
interface ParserContext {
// 当前组件的规则配置
rule: Rule;
// 表单 API 实例
$api: Api;
}merge 参数说明
- 内置组件(如
input、select等)在添加解析器时,请配置merge: true,以免覆盖系统内置的解析逻辑。 - 自定义扩展组件若无默认解析逻辑,可以省略该参数。
通过自定义转换器,您可以灵活处理各种数据格式转换需求,实现表单数据与后端数据的无缝对接,提升开发效率和用户体验。


