数据源
1. 功能说明
平台数据属性统一为dataSource属性,可以直接绑定后端逻辑,获取远程数据。
以下以选择器组件为例:

2. 功能实现
2.1 增加数据源相关属性
向 api.ts 文件中写入数据源相关属性。
以下以选择器组件为例:包含“数据源”、“数据类型”、“文本字段”、“值字段”属性以及重新加载数据源的组件逻辑(reload)。
typescript
@Component({
title: '选择器',
description: '选择器',
})
export class SelectOptions<T, V> extends ViewComponent {
constructor(options?: Partial<SelectOptions<T, V>>) {
super();
}
@Method({
title: '重新加载数据',
description: '重新加载数据'
})
reload(): void {} // 需要提供重新加载数据源的方法
}
// api.ts
export class SelectOptions<T, V> extends ViewComponentOptions {
@Prop({
group: '数据属性',
title: '数据源',
description: '展示数据的输入源,可设置为数据集对象或者返回数据集的逻辑',
docDescription: '列表展示的数据。数据源可以绑定变量或者逻辑。变量或逻辑的返回值可以是数组,也可以是对象。对象格式为{list:[], total:10}',
})
dataSource: { list: nasl.collection.List<T>; total: nasl.core.Integer } | nasl.collection.List<T>;
@Prop({
group: '数据属性',
title: '数据类型',
description: '数据源返回的数据结构的类型,自动识别类型进行展示说明',
docDescription: '列表每一行的数据类型。该属性为展示属性,由数据源推倒得到,无需填写。',
})
dataSchema: T;
@Prop({
group: '数据属性',
title: '文本字段',
description: '选项文本的字段名',
setter: {
concept: "PropertySelectSetter"
}
})
textField: (item: T) => any;
@Prop({
group: '数据属性',
title: '值字段',
description: '选项文本的字段名',
setter: {
concept: "PropertySelectSetter"
}
})
valueField: (item: T) => V = ((item: T) => item.value) as any;;
}2.2 组件内部加载数据和渲染
Vue3
Vue2
React
参考Element Plus Select支持数据源示例。
typescript
// src/hooks/useDataSource.ts
import { defineExpose, ref, toRefs, watch, useAttrs } from 'vue';
/**
* @param props 组件参数
*
* @emits before-load dataSource 远程加载请求前
* @emits load dataSource 远程加载请求后
*
* @return list dataSource 返回的数据
* @return loading 加载状态
*/
export const useDataSource = (props) => {
const {dataSource} = toRefs(props);
const attrs = useAttrs() as any;
const list = ref<Array<any>>([]);
const loading = ref(false);
watch(dataSource, () => {
loadList();
});
// dataSource 加载数据
const loadList = async () => {
if (typeof dataSource.value === 'function') {
loading.value = true;
if (attrs.onBeforeLoad) {
attrs.onBeforeLoad();
}
const data = await dataSource.value({});
list.value = normalizeData(data);
loading.value = false;
if (attrs.onLoad) {
attrs.onLoad();
}
} else {
list.value = normalizeData(dataSource.value);
}
};
/**
* 过滤data
* @param data
*/
const normalizeData = (data) => {
if (Array.isArray(data)) {
return data;
}
if (typeof data === 'object' && Array.isArray(data.list)) {
return data.list;
}
return [];
};
loadList();
return {
list,
loading,
reload: loadList
};
}vue
<template>
<el-select v-bind="$attrs" :loading="loading">
<el-option
v-for="item in list"
:key="lodashGet(item, valueField)"
:label="lodashGet(item, textField)"
:value="lodashGet(item, valueField)"
>
</el-option>
</el-select>
</template>
<script setup lang="ts">
import lodashGet from 'lodash/get';
import { ElSelect, ElOption } from 'element-plus';
import { defineExpose } from 'vue';
import { useDataSource } from '@/hooks/useDataSource.ts';
const props = defineProps({
dataSource: [Array, Function, Object],
dataSchema: { type: String, default: 'entity' },
textField: { type: String, default: 'text' },
valueField: { type: String, default: 'value' },
});
const { list, loading, reload } = useDataSource(props);
defineExpose({
reload
});
</script>