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

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

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

演示地址: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. 该方案只是出于兴趣,如要使用到实际项目中,还望慎重

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

相关推荐
wakangda2 小时前
React Native 集成原生Android功能
javascript·react native·react.js
breaksoftware4 小时前
低代码开源项目Joget的研究——基本概念和应用
低代码
秃头女孩y8 小时前
【React中最优雅的异步请求】
javascript·vue.js·react.js
前端小小王14 小时前
React Hooks
前端·javascript·react.js
迷途小码农零零发14 小时前
react中使用ResizeObserver来观察元素的size变化
前端·javascript·react.js
算法小白(真小白)14 小时前
低代码软件搭建自学第二天——构建拖拽功能
python·低代码·pyqt
码农君莫笑14 小时前
信管通低代码信息管理系统应用平台
linux·数据库·windows·低代码·c#·.net·visual studio
不是鱼18 小时前
构建React基础及理解与Vue的区别
前端·vue.js·react.js
低代码布道师19 小时前
从用户视角出发:用例图分析家政预约小程序
低代码·小程序
飞翔的渴望21 小时前
antd3升级antd5总结
前端·react.js·ant design