DataSet 对象详解
前几章中介绍了 DS 对象概念,本章将介绍以下几个属性并对其扩展对象做详解介绍:
- field
- record
- transport
- dataToJSON
DataSet methods
DataSet 实例化后的对象具有很多方法 - DataSet Methods,用于操纵 DataSet 中的关联对象以及实现各种请求、加载、数据转化等操作。
DataSet 方法操作对象可分三类:
DataSet 本身
- 与后端交互 - query、submit、setQueryParameter、loadData、page …
- 状态、数据获取 - ready、toData、toJSONData…
- 数据定位 - locate、page、first、prePage …
Field 对象
- getField(fieldName) - 获取字段对象
- addField(fieldName, fieldProps) - 更新、新增字段
records数组
- 记录数组的增删选择 - create、delete、remove、select …
- 记录数组的迭代方法 - push、shift、map、forEach …
对应的关联对象也拥有自己的方法属性等。
fields
官网文档描述:字段属性数组,详见Field Props。
字段属性数值,在 DS 实例化后对应配置生成 field 对象,field 对象方法。
如官网 API 文档,field 对象有自己的属性(props)、值(values)、方法(method)。那么这三类 API 能怎么具体在何时使用呢?并且有什么效果呢?
field props
DataSet 配置中对字段信息属性配置。
注意:部分字段属性优先级高于组件属性。 例如 required 属性,字段配置必输,组件配置 required={false},此时存在冲突会应用字段上的配置。 原因在于 DS 可关联多个组件并做提交等与后端交互的操作,控制范围广且状态与后端交互,因此属性冲突时 DS 优先级更高。 以下是开发中几个最常用的属性(关于 Lov/Lookup 类后续做详细说明):
属性名 | 描述 | 类型 | 默认值 |
---|---|---|---|
name | 字段名 | string | |
type | 字段类型,可选值:boolean | number | string | date | dateTime | time | week | month | year | email | url | intl | object | string | string |
required | 是否必选 | boolean | false |
dynamicProps | 动态属性对象。对象为字段属性和返回该字段值的钩子的键值对。 | { fieldProp: ({ dataSet, record, name }) => value } | |
ignore | 忽略提交, 可选值:always- 总是忽略clean- 值未变化时忽略never- 从不忽略 | string | never |
name
对应需要处理的后端字段名
type
字段值类型。用于处理值类型以及组件库内根据 type 关联渲染对应组件类型。
例如上一章 Table active 状态字段,type: ‘boolean’ 表格内渲染组件类型为 Checkbox。
其它对应关系如下:
- number - NumberField
- string - TextField | Select
- date - DatePicker
- dateTime - DateTimePicker
- time - TimePicker
- week - WeekPicker
- month - MonthPicker
- year - YearPicker
- email - EmailField
- url - UrlField
- intl - IntlField
- object - Select | Lov
可以发现以上 type 对应组件类型有多个情况,并且实际应用时可能也需要更多类型的组件支持,那么这种情况组件库如何处理?是否支持?
回答是当然支持。如何支持后续章节结合案例实践吧。
required
是否必输。
配置字段是否必输,如果为 true(必输),那么在使用 DS 提交或者调用相关校验方法时会校验值是否存在。
同类型属性还有:readOnly | disabled …
对应更多自定义校验需求可以使用属性validator -校验器,当返回值为 false 或 涵盖错误信息的字符串,则为校验失败。
dynamicProps
动态属性对象。对象为字段属性和返回该字段值的钩子的键值对。
表面含义,动态配置属性,类型为:{ fieldProp: ({ dataSet, record, name }) => value }
例如上面的必输属性动态配置:
// 当字段满足 xxx 条件时,该字段必输
dynamicProps: {
required: ({ dataSet, record, name }) => {
if(xxx) {
return true;
}
},
}
基本上 field props 均可动态配置,当然有一些特殊属性例如defaultValue,只有在第一次渲染的时候有效,这是 React 的规范,(https://reactjs.org/docs/forms.html#controlled-components)。 这时设置动态默认值需要使用 record 方法 set 或 新建时 create({}) 赋值处理。还有一些特殊情况也不适用使用动态属性。
注意:尽量在必要的场景才使用 dynamicProps,动态属性在组件库内部需要做逻辑判断才能确保属性动态处理正确,无意义的动态属性会造成性能问题。
ignore
忽略提交, 可选值: always - 总是忽略 clean - 值未变化时忽略 never - 从不忽略
默认值:never,含义是字段在于后端交互时,DataSet 提交数据中从不忽略该字段。举个例子:字段名 name,我们需要将修改后的 name 提及给后端,如果当前字段仅前端使用到,不需要通过接口传给后端,那么 ignore 可配置为 always。
field 对象
DataSet 实例化后 field 字段对象常用方法如下。用于处理实例后字段配置或功能的调用。
属性名 | 描述 | 类型 | 默认值 |
---|---|---|---|
get(propsName) | 根据属性名获取属性值 | propsName- 属性名 | any |
set(propsName, value) | 设置属性值 | propsName- 属性名;value- 属性值 | |
reset() | 重置设置的属性 | ||
checkValidity() | 校验字段值 | boolean | |
getValue() | 获取当前记录的本字段值 | any | |
isValid() | 是否校验通过 | boolean | |
getValidationMessage() | 获取校验信息 | string |
注意:field 对象可通过两种方式获取:
- ds.getField(fieldName)
- record.getField(fieldName)
他们的区别在于 ds 获取到的字段对象是 record 中获取的字段对象的基础,record 获取到的字段对象用于满足区别不同数据记录之间对字段的不同配置操作需求。
例如:列表中存在两行数据,存在字段 name 和 age。需求为当输入 age 大于 18 时 name 字段值必输。此时操作就属于当前 record 对象的更新字段对象属性,可写为:record.getField(‘name’).set(‘required ‘, true)。这样便不影响其他未输入和不满足需求 record 字段配置。
record 对象
DataSet 数据源中存储的记录,可以理解成数据库中的一条记录。在DataSet 实例化后初始化成 record 对象,具有值及方法。
record values
将普通数据实例化为保存在 DataSet 中的 record 对象,常用的 record 对象值有以下,更多参考 record values。
属性名 | 描述 | 类型 |
---|---|---|
id | 唯一 ID,自增长的数字 | number |
key | 唯一键,主键字段或唯一索引键字段的值,默认同 id | string | number |
status | 状态, 可选值add | update | delete | sync | observable |
selectable | 可选 | observable |
isSelected | 是否选中 | observable |
isCurrent | 是否当前记录 | observable |
dirty | 数据是否发生变更, 包含级联数据源是否变更 | boolean |
index | 在数据源中的索引 | number |
record methods
日常开发中操作最频繁的就是数据,使用 Pro 组件库后便对应操作数据对象 record。
record 对象的每一个方法使用频率都不低,这里简单介绍一下setState、getState 这对方法组。
属性名 | 描述 | 类型 |
---|---|---|
setState(key, value) | 设置自定义状态值。 | key- 键名或者键值对对象;value- 值 |
getState(key) | 获取自定义状态值。 | key- 键名 |
这对方法和原生 react 自带的 state 管理方法很类似。区别在于其挂载在 record 对象上,什么意思?我们可以将自定义状态值挂载在一条数据对象上。
例如:控制可编辑表格行内编辑。使用原生 state 变量 editing,在处理多条数据的不同可编辑状态时比较麻烦,需要构造对应行及其编辑状态的对象数组。此时使用 record 对象下状态值的自定义,直接调用当前 record.get(‘editing’) 即可区别不同数据不同编辑状态,方便易用。
Transport
DataSet 与后端接口交互的“中间传输站”。
DataSet 中内置了一套默认的接口规范。DataSet 的 name 属性配置可对应后端的 name(约定的相关 key),自动生成约定的 submitUrl, queryUrl, tlsUrl, validateUrl 等。前后端规范统一便不需要配置 “中间站” transport,接口不一致便需要前端配置接口。
例如:
前后端规范统一,前端 DataSet 配置中 name 属性与后端对应。那么调用 ds.query(),对应调用的 queryUrl 为:
/dataset/${this.name}/queries
- submitUrl:
/dataset/${this.name}/mutations
- validateUrl:
/dataset/${this.name}/validate
- submitUrl:
约定生成的 url 格式即为:/dataset/${this.name}/xxx
,且请求类型均为 POST
- 后端有单独的一套规范,可使用:adapterCRUD 配置适配器 - (config: AxiosRequestConfig, type: string) => AxiosRequestConfig;支持全局配置使用。
例如:
const defaultAdapter = (config: AxiosRequestConfig, type: string) => {
// 使用 switch case 或 策略模式处理
switch (type) {
case 'read':
return {
url: 'xxx',
method: 'get',
};
case 'create':
return {
url: `xxx`,
method: 'put',
data: data[0],
};
case 'update':
return {
// url: `xxx`,
method: 'put',
data: data[0],
};
case 'destroy':
return {
url: 'xxx',
data: data[0],
method: 'delete',
};
}
};
- 后端规范不一,情况多变;前端需要特殊处理:在 DataSet 配置中配置 transport 或对应 url 属性。例如:
// 配置 transport
transport: {
create: ({ data }) => ({
url: `xxx`,
data: data[0],
}),
update: ({ data, params }) => ({
url: `xxx`,
method: 'put',
data: data[0],
params: {...params, ss: 'xx'}
}),
},
// 仅配置queryUrl
queryUrl: 'xxx'
注意:组件库内默认请求类型均为 POST,所以在调用 DataSet 设置相关查询参数的方法时,在 transport 处理返回 axiosConfig 的回调中,setQueryParameter(para, value) 设置查询参数值均在 data 对象中,method 类型为 GET 时,需要注意参数的转化传递。
dataToJSON
dataToJSON 是 DataSet 的属性配置之一。用于配置 DataSet 数据转化规则。
在调用 DataSet.toJSONData() 时应用,配置后与后端数据交互同理。
枚举值 | 说明 |
---|---|
dirty | 只转换变更的数据,包括本身无变更但级联有变更的数据 |
selected | 只转换选中的数据,无关数据的变更状态 |
all | 转换所有数据 |
normal | 转换所有数据为普通 json,不会带上status, id 等附加字段,也不会出现临时删除的数据, 一般用于大 JSON 字段 |
dirty-self | 同 dirty, 但不转换级联数据 |
selected-self | 同 selected, 但不转换级联数据 |
all-self | 同 all, 但不转换级联数据 |
normal-self | 同 normal, 但不转换级联数据 |
本章挑选几个重点属性、方法做了场景描述,下面我们来实践一下,对我们上一章的 Table 做一些功能扩展。