低代码在线拖拽公共组件的鬼点子,快来看看吧

如果你在项目中用过阿里低代码引擎,或尝试在项目中使用,那么你或许就会有这样的想法:能不能像前端框架中封装的公共组件一样,拖拽配置出来一个组件公用?而不是每次需要新的公共组件的时候,都要按照官方文档,去重新新建一个项目,按照文档说明去配置去开发,最后再打包引入到原工程。

基于上面的场景,笔者通过一个鬼点子实现了该功能,当前实现的方案不支持出码模块。

演示地址:www.zzusp.asia (备) http://124.222.119.198/

代码仓库:github.com/gitmyname/o...

注:阅读本篇文章需要对低代码引擎有一定的了解,如:渲染、appHelper、低代码组件开发

先说下整体思路

  1. 在原项目中实现渲染模块的逻辑,传入页面的code可以渲染对应页面(其实就是根据code获取对应的schema,然后动态渲染)
  2. 将渲染模块作为一个渲染方法的返回值,通过appHelper传入引擎中
  3. 新建项目,开发一个用于接收动态渲染的低代码组件(渲染组件),并配置到引擎的组件库中
  4. 拖拽渲染组件,并在引擎源码面板中,将渲染方法渲染组件绑定即可

1. 渲染模块代码

js 复制代码
<Renderer page={page} />

展开查看代码

js 复制代码
import React, {useState, useEffect} from 'react';
import {Loading} from '@alifd/next';
import mergeWith from 'lodash/mergeWith';
import isArray from 'lodash/isArray';
import {buildComponents, assetBundle, AssetLevel, AssetLoader} from '@alilc/lowcode-utils';
import ReactRenderer from '@alilc/lowcode-react-renderer';
import {injectComponents} from '@alilc/lowcode-plugin-inject';
import appHelper from '../../appHelper';
import {
  getProjectSchemaFromDb,
  getPackagesFromAssets
} from '../../services/schemaService';

const Renderer = (props) => {

  const {page} = props;

  const [data, setData] = useState({});

  useEffect(() => {
    setData({});
    init();
  }, [page])

  async function init() {
    console.log('Renderer Page ' + page);

    const projectSchema = await getProjectSchemaFromDb(page);
    const packages = await getPackagesFromAssets();
    setData({});
    const {
      componentsMap: componentsMapArray,
      componentsTree,
      i18n,
      dataSource: projectDataSource,
    } = projectSchema;
    const componentsMap: any = {};
    componentsMapArray.forEach((component: any) => {
      componentsMap[component.componentName] = component;
    });
    const pageSchema = componentsTree[0];

    const libraryMap = {};
    const libraryAsset = [];
    packages.forEach(({package: _package, library, urls, renderUrls}) => {
      libraryMap[_package] = library;
      if (renderUrls) {
        libraryAsset.push(renderUrls);
      } else if (urls) {
        libraryAsset.push(urls);
      }
    });

    const vendors = [assetBundle(libraryAsset, AssetLevel.Library)];

    // TODO asset may cause pollution
    const assetLoader = new AssetLoader();
    await assetLoader.load(libraryAsset);
    const components = await injectComponents(buildComponents(libraryMap, componentsMap));

    setData({
      schema: pageSchema,
      components,
      i18n,
      projectDataSource,
    });
  }

  const {schema, components, i18n = {}, projectDataSource = {}} = data as any;

  if (!schema) {
    return <Loading fullScreen tip={<span style={{color: '#5584ff'}}>Loading...</span>}>
      <div className="lowcode-plugin-sample-preview" style={{ minHeight : '90vh' }}></div>
    </Loading>;
  }

  function customizer(objValue: [], srcValue: []) {
    if (isArray(objValue)) {
      return objValue.concat(srcValue || []);
    }
  }

  return (
    <div className="lowcode-plugin-sample-preview" style={{ minHeight : '90vh' }}>
      {!schema ? <Loading style={{ width : '100%', height : '90vh' }}/> : <ReactRenderer
        className="lowcode-plugin-sample-preview-content"
        style={{ height : '100%' }}
        schema={{
          ...schema,
          dataSource: mergeWith(schema.dataSource, projectDataSource, customizer),
        }}
        components={components}
        messages={i18n}
        appHelper={appHelper}
      />
      }
    </div>
  );

};

export default Renderer;

2. 通过appHelper将渲染传入引擎

js 复制代码
appHelper.utils.renderer = (page) => {
  return <Renderer page={page} />
};

3. 实现低代码组件-渲染组件

shell 复制代码
# 新建一个低代码组件项目并启动
npm init @alilc/element your-element-name
cd your-element-name
npm install
npm start

渲染组件核心代码index.tsx

js 复制代码
import * as React from 'react';

interface ComponentProps {
  name: string,
  element: any,
  onRender: Function|undefined
}

export default class CustomRendererComponent extends React.Component<ComponentProps> {

  constructor(props) {
    super(props);
    this.state = {
      name: props.name,
      element: props.element,
      onRender: props.onRender
    };
    this.ref = React.createRef();
  }

  componentDidMount() {
    if (this.state.onRender !== undefined) {
      this.state.onRender(this.ref);
    }
  }

  render() {
    return (
      <div className="CustomRendererComponent">
        <div ref={this.ref}>
          {this.state.element || 'no element'}
        </div>
      </div>
    )
  }

}

引入到原项目

js 复制代码
打包新建的低代码组件项目,通过本地拷贝也好,发布到npm仓库再install也好,将低代码组件的资源引入到原项目中。这部分阅读下官方文档,这里就不详细说明了。

然后修改原项目中的assets.json,将低代码组件配置到引擎中,现在在组件库面板

{
  "packages": [
    ...
  ],
  "components": [
    ...
    {
      "exportName": "PluginCustomRendererMeta",
      "npm": {
        "package": "plugin-custom-renderer",
        "version": "0.1.0"
      },
      "url": "./lowcode/meta.js",
      "urls": {
        "default": "./lowcode/meta.js"
      },
      "advancedUrls": {
        "default": [
          "./lowcode/meta.js"
        ]
      }
    }
  ],
  "sort": {
    "groupList": [
      "精选组件",
      "原子组件",
      "低代码组件"
    ],
    "categoryList": [
      "基础元素",
      "布局容器类",
      "表格类",
      "表单详情类",
      "帮助类",
      "对话框类",
      "业务类",
      "通用",
      "导航",
      "引导",
      "信息输入",
      "信息展示",
      "信息反馈",
      "常用"
    ]
  },
  "groupList": [
    "精选组件",
    "原子组件",
    "低代码组件"
  ],
  "ignoreComponents": {}
}

启动后就可以在组件面板中看到我们新建的低代码渲染组件了,如下图:

4. 配置低代码渲染组件

按照下图的三步配置后,就可以渲染其他已经配置好的页面

(图中的dashboard是配置好的首页的code)

结语

  1. 该方案还不支持出码模块,根据官方文档重新开发出码模块是否能够达到预期效果未知
  2. 还未实现传参,但有可行方案,如:通过appHelper
  3. 该方案只是出于兴趣,如要使用到实际项目中,还望慎重

本文正在参加阿里低代码引擎征文活动

相关推荐
Java陈序员8 小时前
轻量运维面板!一款现代化的服务器控制面板工具!
运维·服务器·python·react.js·github
光影少年11 小时前
RN首屏加载速度优化全方案
react native·react.js·掘金·金石计划
前端精髓13 小时前
React 更新 state 中的对象
javascript·react.js·ecmascript
10share19 小时前
我为什么用 React 重写了一个 VitePress
前端·react.js
天道kabuto19 小时前
前端每日知识点:React 与 Vue Diff 算法对比 · 完整总结
vue.js·react.js·前端框架
moMo19 小时前
React 全栈实战:从组件到鉴权的完整指南
react.js
梦梦代码精1 天前
《回收租赁系统技术选型避坑指南:业务闭环与二开自由度详解》
开发语言·低代码·docker·开源·代码规范
光影少年2 天前
如何实现RN 多环境、多渠道打包
前端·react native·react.js
云上工程笔记2 天前
AstraFlow + React/Vite:如何用自然语言开发并部署一个 AI 咖啡网站原型
前端·人工智能·react.js