一、前言
在项目中用vue3
有一段时间了,发现有一些代码,对form组件的处理不是很简洁,导致每次需求变更字段,都需要花费更多时间去处理,在这里分享一下比较好的写法。
二、form表单处理
2.1、需求场景假设
2.2、新增form表单
2.2.1、reactive和ref如何选择
我们希望表单中的每一个字段都具备响应式。
在
vue3
中reactive和ref都可以手动进行声明,通常像这种需要传一个对象给后端的,用reactive比较合适。
如果使用ref的话,每次在script中改变值的时候,都需要每一个字段单独去改变,写法比较冗余;同理,如果使用reactive也还是单个去赋值的话
// ref冗余的写法
username.value = 'xxx'
password.value = 'xxx'
adress.value = 'xxx'
// reactive冗余的写法
const formState = reactive(
{
username: '',
password: '',
address: '',
}
)
formState.username = 'xxx'
formState.password = 'xxx'
formState.adress = 'xxx'
这样的写法带来的一个后果是,后续每次增加或修改字段的时候。需要在每个用到的地方,针对每个值都改一变,比较容易出错。
2.2.2、如何对proxy对象赋值
当我们使用 const formState = reactive(xxxObject)的时候,返回的其实是一个proxy对象。
如果我们使用vue2
的方式进行对象赋值this.formState = xxx,proxy对象的引用就改变了,则会丢失他的响应式,导致html中无法正常的改变表单值。
如果是单个字段,我们可以使用formState.username = 'xxx'
这种方式进行处理。
多个字段的话,则可以使用Object.assign(formState, xxxObject)
2.2.3、如何重置对象
回想vue2
中,我们在data函数中定义完一个对象后,则可以使用const { xxxObject } = this.$options.data()
,来得到一个只有初始值的对象。
vue3
的reactive似乎没有提供这么便捷的api。
但是问题不大,我们在定义对象的时候,像vue的data函数那样,把他定义成一个返回对象的函数即可。
const getFormState = () => {
return {
username: '',
password: '',
address: '',
}
}
const formStateReactive = reactive(getFormState())
// 重置对象
Object.assign(formStateReactive, getFormState())
2.3、编辑form表单
编辑时,会把列表中某一行的数据,传到form表单中。
控制对话框显示/隐藏的字段visible
可以使用ref。
某一行的数据curRowData
,还是传proxy的对象过去。
/* 声明 start */
const props = defineProps({
visible: {
type: Boolean,
default: false,
},
formType: {
type: String,
default: '',
},
curRowData: {
type: Object,
default: () => ({}),
},
})
const getFormState = () => {
return {
username: '',
password: '',
address: '',
}
}
const formStateReactive = reactive(getFormState())
// 在父组件使用ref的值,在子组件中需使用toRef来对props进行解构,保持响应式
const { visible, formType } = toRefs(props)
// 普通对象或者是proxy对象则直接解构即可
const { curRowData } = props
/* 声明 end */
// 当对话框显示时,且状态为【编辑】,则合并传过来的对象
watchEffect(() => {
if (visible.value) {
if (formType.value === 'edit') {
Object.assign(formStateReactive, curRowData)
}
}
})
- 在父组件使用ref的值,在子组件中需使用toRef来对props进行解构,保持响应式
- 普通对象或者是proxy对象则直接解构即可
2.4、compositionAPI的使用场景
这时候产品经理加了需求,说要再增加一个表单,逻辑和之前的一致。只给他编辑用户名,其他字段都改为禁用的状态。
如果产品经理和需求都砍不掉的话,我们可以考虑把代码进行抽离,来更好地使用compositionAPI
特性。
在vue2
中,基于optionsAPI的写法下,我们如果想组合一些重复的代码逻辑,Mixin是一个相对还可以的选择。但是Mixin也会带来很多来源混乱,导致bug难以排查的问题。
compositionAPI就舒服了。比如我要处理表单保存、校验相关的逻辑,就可以直接声明一个公共的js,form.js
。
// 这是一个公共的js
// 保存表单
export const saveForm = () => {}
// 校验表单
export const rules = () => {}
在用到的组件中直接import即可。
三、总结
不得不说,vue3
的compositionAPI + script setup 写起来太爽了。不过写的时候,也要注意按业务逻辑,来抽离出不同的代码块。不然看起来会比较vue2
的更乱,这样就违背了使用vue3
的初衷了。