lowcode-render
v0.0.6
Published
## Usage ### 入口: ```vue <script setup lang="ts"> import { RenderEngine, EnginePropsType } from "@/components/engine"; import * as ElComponents from "element-plus"; import { addBaseFunc } from "./BaseActions";
Downloads
3
Readme
Vue3 lowcode-render
Usage
入口:
<script setup lang="ts">
import { RenderEngine, EnginePropsType } from "@/components/engine";
import * as ElComponents from "element-plus";
import { addBaseFunc } from "./BaseActions";
const schema = {
componentName: "ElButton",
props: {
innerText: {
type: EnginePropsType.Model,
value: "span",
defaultValue: "xxxxxx",
},
type: "danger",
onClick: {
type: EnginePropsType.Action,
actionKey: "clickTest",
},
},
};
</script>
<template>
<RenderEngine
:schema="schema" // schema,描述页面UI及逻辑
:components="ElComponents" // 渲染使用到的组件Map
:add-action-func="addBaseFunc" // 自定义动作
/>
</template>
组件定义:
import * as ElComponents from "element-plus";
// 此处使用element-plus作为渲染组件库,格式{name: ComponentClass}
动作定义:
function,入参形如{getModel, setModel, remoteKey}
, 返回Map{actionKey: function}
import { get } from "lodash";
import { computed } from "vue";
export function addBaseFunc({ getModel, setModel, remoteKey }: ActionFunc) {
const router = useRouter();
return {
jump(params: RouterParams) { // 路由跳转动作
router.push({
path: params.path,
query: params.query ?? {},
});
},
toast(params: ToastParams) { // toast动作
(ElMessage as any)[params.type]?.(params.msg);
},
dialog(params: DialogParams) { // Modal动作
setModel(params.model, !getModel(params.model));
},
async fetch(params: FetchParams) { // 网络请求
let customParams = {};
if (params.fetchKey) {
customParams = params.params ?? {};
params = remoteKey[params.fetchKey];
}
const {
url = "",
method = "",
params: fetchParams,
confirmText,
} = params;
if (confirmText) {
ElMessageBox.confirm(confirmText, "提示", {
confirmButtonText: "确认发送",
}).then(async () => {
await sendRequest(
url,
method,
[{ ...fetchParams, ...customParams }],
params.lrMap
);
});
} else {
await sendRequest(
url,
method,
[{ ...fetchParams, ...customParams }],
params.lrMap
);
}
},
toggle() { // 添加computed追踪依赖变化
const model = getModel("table1[0]");
model.cateId = computed(() => `${getModel("form1.cateId")}_table`);
setModel("condition", !getModel("condition"));
},
clickTest() { // 测试例子
setModel("span", "zzzz");
},
};
}
整体方案
- 组件库,schema,Action(逻辑)分离,均支持自定义实现
- 使用vue3 reactive保持数据响应性,顶层数据管理,数据驱动,实现数据及数据修改和UI分离
schema定义
节点定义
interface Component {
id?: string;
componentName: string;
props: {[key: string]: Props || any}; // 非Props类型时type默认为plain,节省数据开销
condition: {}; // 渲染条件
loop: [] || {}; // 循环数据,比如select下的options描述
slots: {}; // 插槽
children: Component[];
}
数据类型
无type情况下直接取值
export const EnginePropsType = {
Plain: 'PLAIN', // 普通类型
Model: 'MODEL', // model里面的key
Loop: 'LOOP', // 循环绑定
VModel: 'VMODEL', // 双向绑定
Action: 'ACTION', // action里面的key
Slot: 'SLOT', // JSX插槽
SlotContext: 'SLOT_CONTEXT', // 插槽入参
JSFunction: 'JS_FUNCTION' // 自定义函数
};
动态数据
取模型中对应的字段(key)
{
type: EnginePropsType.Model,
value: 'table1',
defaultValue: []
}
循环
{
type: EnginePropsType.Loop,
value: 'value' // key名
}
双向绑定
VModel:比较特殊,需单独绑定,指定form和field
{
type: EnginePropsType.VModel,
form: 'form1',
field: 'select'
}
Action
{
type: EnginePropsType.Action,
actionKey: 'reset',
params: { sets: [{ localKey: 'table1', remoteKey: 'data.cate' }], formKey: 'form1' } // 传入action fun中的参数
}
Slot及SlotContext:
{
slots: {
default:
[
{
componentName: 'img',
key: '19',
props: {
src: {
type: EnginePropsType.SlotContext,
value: 'row.imgUrl'
},
style: {
width: '100px'
}
}
}
]
}
}