利用框架Render特性,我做了一个与业界不一样的低代码且跨框架的UI SDK。

6,049 阅读3分钟

如果你想看更多的资讯与学习教程,请到b站关注 傻梦兽 UP主,我在b站等你喔!

【傻梦兽的个人空间-哔哩哔哩】 b23.tv/2B9INMH

与标题一样,最近一个月我收到一个需求。需要做一个跨段的组件库,而且这个ui库是支持sdk的修改功能并且是跨平台的。

在面对这个需求之前,我和你们的大多数的人的思路是一样的,那就是想基于Web Component去完成这个需求,但后面了解下后Web Component并没有Asp,PHP,React这类HTML切入脚本语言这么强大。

我最终还是选择了基于React进行一波改造,当然并不会选择React因为它比较大,我最终把框架指向了Preact或fre。在强大的社区面前我最终选择了基于Preact。

使用这个ui sdk之后,我们可以做什么事情?因为这是一个基于面向对象管理。所以在低代码会有更好的管理与修改,我们先看看代码编写风格。如果你是做个java项目或者做个ng这一类面向对象开发的经验的话会很容易看出我在做什么。

// 创建一个渲染挂载的对象
const app = document.getElementById("app") as HTMLElement;

const reui = new ReUI(app);

// 初始化数据

reui.start();

reui.SetMode(UIMode.Editor);

// 创建page对象
const page = reui.AddPage()

// 目前业务我只实现了浮动ui的一个业务组件
const f = page.CreateFloatUI();

// 在这个浮动UI创建一个Button
f.CreateButton()

// 设置他的属性
f.SetDx(100)

f.SetDy(100)

f.SetRounded(16);

f.CreateMaterialSelect();

f.SetPosition(Position.TopLEft);

const t = f.CreateText() as TextComponentStore;
t.SetStyleToH2();

可以看出我是把我们平时操作低代码的JSON对象全部以对象的形式进行操作。 最后我们只需要这些类的依赖关系进行序列化与反序列化即可。

console.log(JSON.stringify(reui.GetData(), null, 3));

/**

* 将 sotre 反序列化

*/

public GetData() {

    const pages = StoreUntis.GetPageUIList(this.store);
    const components = pages.map(p => {
        return {
            tag: p.tag,
            uuid: p.GetUUID(),
            children: p.components.value.map(v => v.Serialization())
        }
    })

    const options = {};
    return {
        components,
        options
    }
}

那如何进行initData呢?主要的思路

initData(data: UIData) {

    if (data && data.hasOwnProperty("components")) {

        this.views.value = this.createComponentStores(data.components);

    }

}


createComponentStores(componentsData: ComponentData[]) {

const componentStores: ComponentStore[] = [];

componentsData.forEach(componentData => {

if (!componentData.tag) {
    return;
}

const ComponentStoreBuilder = ComponentStoreMap.get(componentData.tag);
    if (!ComponentStoreBuilder) {
    return;

}

const component = new ComponentStoreBuilder(componentData);

if (componentData.hasOwnProperty("children")) {

 component.setCompoents(this.createComponentStores(componentData.children));

}

componentStores.push(component);

});

return componentStores;

}

App.tsx

export const Application = () => {
    const views = ReUI.instance.store.views;
    return <div>{VnodeDOM.RenderComponents(views.value)}</div>;
};

是的我们实现了一个signals功能,然后通过subscribe的方式进行去触发preact的渲染render方法。然后每一个组件都是监听一个props.

import './styles/index.css';

import classnames from "classnames";

import { h } from "preact";

import { ImageComponentStore } from ".";

import { RenderComponentProps } from "../../../core/props";

interface ImageProps extends RenderComponentProps {

component: ImageComponentStore

}

export const Image = (props: ImageProps) => {

const { component } = props;

const { uri, href, isEditorMode } = component;

const handleClick = () => {
    if (isEditorMode) {
    } else {
    handlerPreviewMode();
    }
}


const handlerPreviewMode = () => {
    if (href) {
        window.open(href);
    }
}


return (
    <img className={classnames(
    'w-full', 'rounded-lg', 'realibox-image', 'flex', 'justify-center', 'items-center',
    'bg-contain', 'bg-no-repeat', 'bg-center'
    )}
    onClick={handleClick}
    src={uri}
    draggable={false}
    />
)

};

为了让组件可以添加扩展必须继承一个ComponentStore

export class ImageComponentStore extends ComponentStore {
    
    tag = ComponentType.Image;
    // uri
    private _uri = signal("");
    // ... codeing
    
    constructor(componentsData: ImageComponentData) {
        super(componentsData);
        this.update({
            uri: componentsData.uri,
            href: componentsData.href,
        });

    }

    public SetUrl(value: string) {
        this.uri = value;
    }
  
    public Serialization() {
        return {
            tag: this.tag,
            uuid: this.GetUUID(),
            uri: this.uri,
            href: this.href
        }
    }

}

最后我们看看成果。

image.png 我们可以像低代码一样操作它。

image.png

甚至可以在Vue的团队里面通过我给出的的GetData序列化,在Vue项目里面通过initData方法进行反序列化渲染出来,并且带有跟随热点的功能。

image.png