基于Vue3做一套适合自己的状态管理(四)Model的正确的打开方式
计划章节
- 基类:实现辅助功能
- 继承:充血实体类
- 继承:OptionApi 风格的状态
- Model:正确的打开方式
- 组合:setup 风格,更灵活
- 注册状态的方法、以及局部状态和全局状态
- 列表页面需要的状态
- 当前登录用户的状态
充血实体类的 Model 要不要来一个?
Vue提供了非常方便的双向绑定的功能(注意这是单向数据流),我们只要再加上几个常用功能,就是一个充血实体类了。
表单需要哪些功能?
我们想想一个表单需要哪些功能?
- 重置表单 —— 使用$reset()实现
- 修改前赋值 —— 使用$state 实现
- 提交 —— 单独做一个函数
- 数据验证 —— 交给UI库的表单组件
先做个语法糖
/**
* 给 BaseObject 套个壳,加上 reactive 实现响应性。
* @param fun 必须使用函数
* @returns
*/
export default function createModel<T>(fun: () => T): T & IState {
const re = new baseObject(fun)
const ret = reactive(re)
return ret as T & IState
}
语法糖有几个目标:
- 简化代码,实例、套上 reactive 变成一行
- 组合类型
- 类型判断
绑定表单设置事件
<el-form :model="person" label-width="120px" style="width: 500px;">
<el-form-item label="名称">
<el-input v-model="person.name" />
</el-form-item>
<el-form-item label="年龄">
<el-input-number v-model="person.age" />
</el-form-item>
<el-form-item label="型号">
<el-select v-model="person.region" placeholder="请选择一个型号">
<el-option label="大号" value="one" />
<el-option label="小号" value="two" />
</el-select>
</el-form-item>
<el-form-item label="选择日期">
<el-col :span="11">
<el-date-picker
v-model="person.date1"
type="date"
placeholder="选择日期"
style="width: 100%"
format="YYYY年MM月DD日"
value-format="YYYY-MM-DD"
/>
</el-col>
<el-col :span="2" class="text-center">
<span class="text-gray-500">-</span>
</el-col>
<el-col :span="11">
<el-time-picker
v-model="person.date2"
placeholder="选择时间"
style="width: 100%"
format="HH:mm:ss"
value-format="HH:mm:ss"
/>
</el-col>
</el-form-item>
<el-form-item label="选择">
<el-switch v-model="person.switch" />
</el-form-item>
<el-form-item label="多选">
<el-checkbox-group v-model="person.checks">
<el-checkbox label="Online activities" name="checks" />
<el-checkbox label="Promotion activities" name="checks" />
<el-checkbox label="Offline activities" name="checks" />
<el-checkbox label="Simple brand exposure" name="checks" />
</el-checkbox-group>
</el-form-item>
<el-form-item label="单选">
<el-radio-group v-model="person.radio">
<el-radio label="Sponsor" />
<el-radio label="Venue" />
</el-radio-group>
</el-form-item>
<el-form-item label="说明">
<el-input v-model="person.resource" type="textarea" />
</el-form-item>
<el-form-item>
<el-button type="primary" @click="onSubmit">提交</el-button>
<el-button type="primary" @click="onSubmit2">提交(准备下一条)</el-button>
<el-button @click="reset" >重置(调用函数)</el-button>
<el-button @click="person.$reset()" >重置(直接在template里)</el-button>
</el-form-item>
</el-form>
使用UI库的 el-form 制作一个表单,绑定数据。重置事件可以直接使用 xxx.$reset()
。
代码部分
// 定义一个类型
type Person = {
name: string,
age: number,
region: string,
date1: string,
date2: string,
switch: boolean,
checks: string[],
radio: string,
resource: string
}
// 创建一个 Model ,类似 reactive 的用法
const person = Model<Person>(() => {
return {
name: 'Model的演示',
age: 10,
region: '',
date1: '',
date2: '',
switch: false,
checks: ['Promotion activities'],
radio: '',
resource: ''
}
})
// 重置
const reset = () => {
person.$reset()
}
// 加载指定的记录,绑定表单
const load = () => {
axios.get('./user.html?id=100').then((res: any) => {
person.$state = res.data
})
}
// 提交表单,然后重置表单
const onSubmit = () => {
// 模拟提交
axios.post('/user.html', person).then(function (res: any) {
// 重置表单
person.$reset()
})
.catch(function (error: any) {
console.log(error)
})
}
// 提交表单,然后保留预设值
const onSubmit2 = () => {
// 保存需要保留的表单值的副本
const old = {
switch: person.switch,
checks: [...person.checks],
radio: person.radio
}
axios.post('/user.html', person).then(function (res: any) {
// 重置表单
person.$reset()
// 设置需要保留的字段值
person.$patch(old)
})
.catch(function (error: any) {
console.log(error)
})
}
- 提交的部分没有做处理,直接使用 axios 的基础用法做演示。
- 创建Model的时候,需要使用函数的方式,因为重置数组需要使用函数的方式。
- 提交的action没有做到Model内部,感觉没有必要,放在外部更灵活。
小结
感觉似乎没有多大的封装必要,不过嘛,写代码,能省一点就省一点,因为我懒。。。
如果一定要把提交的action做的Model里面的话,那么可以使用OptionState。
源码
在线演示
转载自:https://juejin.cn/post/7237375391130992700