状态(State)模式的定义:对有状态的对象,把复杂的“判断逻辑”提取到不同的状态对象中,允许状态对象在其内部状态发生改变时改变其行为。
State抽象状态角色
ConcreteState具体状态角色
Context环境角色
eladmin框架混入及封装用的比较多,导致我也不能很具体的判断出来具体的角色指的是谁,如果有知道的还请留言告诉我,谢谢。
在eladmin中,框架对数据的新增和表单的编辑、删除都通过状态模式去处理了部分逻辑判断。框架并不是针对某个具体的组件进行的状态处理,而是针对的整个过程进行的状态处理。不同组件通过该过程的不同状态,也会有不同的表现形式,例如按钮的loading显示、表单的标题与显示、方法处理的逻辑等。
下面主要以新增数据为例,具体介绍下eladmin中状态模式的实现。
在eladmin中的状态定义
// src/compents/Crud/crud.js
/**
* CRUD状态
*/
CRUD.STATUS = {
NORMAL: 0,
PREPARED: 1,
PROCESSING: 2
}
关键组件
// src/compents/Crud/CRUD.operation.vue
<template>
...
<el-button
v-if="crud.optShow.add"
v-permission="permission.add"
class="filter-item"
size="mini"
type="primary"
icon="el-icon-plus"
@click="crud.toAdd"
>
新增
</el-button>
...
</template>
<script>
// 该处通过混入的方式将crud的方法引进来
import CRUD, { crud } from '@/compents/Crud//crud.js'
export default {
mixins: [crud()],
}
</script>
这里主要混入的是一些逻辑处理的方法、CRUD状态定义和一些关键的data数据
混入后的关键属性有下面这些
// src/compents/Crud/CRUD.operation.vue
<template>
...
<el-button
v-if="crud.optShow.add"
v-permission="permission.add"
class="filter-item"
size="mini"
type="primary"
icon="el-icon-plus"
@click="crud.toAdd"
>
新增
</el-button>
...
</template>
<script>
export default {
data() {
return {
// 通过混入进来的
// ... 省略多余的属性
status: {
add: CRUD.STATUS.NORMAL,
edit: CRUD.STATUS.NORMAL,
// 添加或编辑状态
// 表单、按钮loading等组件的状态都是根据这里判断的
get cu() {
if (this.add === CRUD.STATUS.NORMAL && this.edit === CRUD.STATUS.NORMAL) {
return CRUD.STATUS.NORMAL
} else if (this.add === CRUD.STATUS.PREPARED || this.edit === CRUD.STATUS.PREPARED) {
return CRUD.STATUS.PREPARED
} else if (this.add === CRUD.STATUS.PROCESSING || this.edit === CRUD.STATUS.PROCESSING) {
return CRUD.STATUS.PROCESSING
}
throw new Error('wrong crud\'s cu status')
},
// 标题,控制表单Dialog组件标题在不同状态下的显示
get title() {
return this.add > CRUD.STATUS.NORMAL ? `新增${crud.title}` : this.edit > CRUD.STATUS.NORMAL ? `编辑${crud.title}` : crud.title
}
}
}
},
methods:{
// ... 省略多余的方法
/**
* 启动添加
*/
toAdd() {
// 重置表单数据
crud.resetForm()
// 对自定义钩子进行处理,如果设置了就执行
if (!(callVmHook(crud, CRUD.HOOK.beforeToAdd, crud.form) && callVmHook(crud, CRUD.HOOK.beforeToCU, crud.form))) {
return
}
// 更改add的状态,从NORMAL变为PREPARED
crud.status.add = CRUD.STATUS.PREPARED
// 此时会弹出来el-dialog。该弹框通过:visible.sync="crud.status.cu > 0"控制显示
// 对自定义钩子进行处理,如果设置了就执行
callVmHook(crud, CRUD.HOOK.afterToAdd, crud.form)
callVmHook(crud, CRUD.HOOK.afterToCU, crud.form)
},
/**
* 提交新增/编辑
*/
submitCU() {
if (!callVmHook(crud, CRUD.HOOK.beforeValidateCU)) {
return
}
// 找到当前根据status显示的form组件,并进行校验
crud.findVM('form').$refs['form'].validate(valid => {
if (!valid) {
return
}
// 是否执行钩子
if (!callVmHook(crud, CRUD.HOOK.afterValidateCU)) {
return
}
// 根据状态去判断具体的执行方法
if (crud.status.add === CRUD.STATUS.PREPARED) {
crud.doAdd()
} else if (crud.status.edit === CRUD.STATUS.PREPARED) {
crud.doEdit()
}
})
},
/**
* 执行添加
*/
doAdd() {
// 自定义钩子
if (!callVmHook(crud, CRUD.HOOK.beforeSubmit)) {
return
}
// 更改整个添加过程的状态为PROCESSING
crud.status.add = CRUD.STATUS.PROCESSING
// 调取添加接口(此处eladmin做了一定处理,通过crudMethod和其属性即可调取自己定义的接口地址)
crud.crudMethod.add(crud.form).then(() => {
// 成功后将状态更改为初始状态 = 关闭表单,停止loading
crud.status.add = CRUD.STATUS.NORMAL
crud.resetForm()
crud.addSuccessNotify()
callVmHook(crud, CRUD.HOOK.afterSubmit)
crud.toQuery()
}).catch(() => {
// 出错后就更改为PREPARED状态(新增的第二个状态,此时表单仍然存在)
crud.status.add = CRUD.STATUS.PREPARED
callVmHook(crud, CRUD.HOOK.afterAddError)
})
},
}
}
</script>
简单来说,eladmin通过状态模式针对整个添加的流程做了如下规定:
NORMAL阶段
点击新增,进入PREPARED阶段
点击确定,进入PROCESSING阶段
整个过程涉及到的组件有很多,只不过表单和按钮是最显眼的,并且按钮有很多个。
框架通过状态模式将很多按钮的判断逻辑抽离了出来,减少了不少工作量。
通过状态的判断去控制了各个组件自己的表现形式,在后期维护时也更加容易。
后面有人接手的话也只需要关注关键方法的逻辑。
而不是散落在各个组件中的小按钮和表单样式的逻辑了(假如不使用该模式)。