前端:從零開發一款可視化搭建框架

blank

前端:從零開發一款可視化搭建框架

去年上線的可視化編輯器

  • 出碼能力
  • 組件交互
  • 數據源管理
  • 組件商店
  • 佈局能力
  • 常用功能集成

上面的這些功需求已經在但是為了讓更多的人能低成本的擁有自己的可視化搭建系統,我們團隊的大佬花了非常多的時間研究和沈淀,最近也開源了一款可視化搭建框架

blank

可視化搭建框架基本使用和技術實現

為了讓大家更好的理解可視化搭建框架,我這裡舉幾個形象的例子:

  1. antd

blank

我們都知道

  1. GrapesJS
blank

GrapesJS

  1. dooringx-lib
blank

dooringx-lib

之所以要介紹它們的區別,是因為之前有很多朋友對這塊概念理解的不是很清晰,在了解了

1.技術棧

在分享框架實現思路之前當然要自報家門,框架實現上我們還是採用熟悉的如果你是

2.基本使用方式

在開始深入之前我們先看看如何使用這款框架,我們只需要按照如下方式即可安裝使用:

npm/yarn  install dooringx-lib

同時我們還提供了基礎的使用demo,方便大家在自己的工程中快速上手:

# 克隆項目# cnpmjs # 克隆项目# cnpmjs git clone https://github.com.cnpmjs.org/H5-Dooring/dooringx.git # or git clone https://github.com/H5-Dooring/dooringx.git # 进入项目目录cd dooringx # 安装依赖yarn install # 启动基础範例yarn start:example # 启动dooringx-lib yarn start # 启动dooringx doc 文档yarn start:doc yarn build git clone https://github.com.cnpmjs.org/H5-Dooring/dooringx.git # 克隆项目# cnpmjs git clone https://github.com.cnpmjs.org/H5-Dooring/dooringx.git # or git clone https://github.com/H5-Dooring/dooringx.git # 进入项目目录cd dooringx # 安装依赖yarn install # 启动基础範例yarn start:example # 启动dooringx-lib yarn start # 启动dooringx doc 文档yarn start:doc yarn build # or # 克隆项目# cnpmjs git clone https://github.com.cnpmjs.org/H5-Dooring/dooringx.git # or git clone https://github.com/H5-Dooring/dooringx.git # 进入项目目录cd dooringx # 安装依赖yarn install # 启动基础範例yarn start:example # 启动dooringx-lib yarn start # 启动dooringx doc 文档yarn start:doc yarn build git clone https://github.com/H5-Dooring/dooringx.git # 克隆项目# cnpmjs git clone https://github.com.cnpmjs.org/H5-Dooring/dooringx.git # or git clone https://github.com/H5-Dooring/dooringx.git # 进入项目目录cd dooringx # 安装依赖yarn install # 启动基础範例yarn start:example # 启动dooringx-lib yarn start # 启动dooringx doc 文档yarn start:doc yarn build # 進入項目目錄cd dooringx # 克隆项目# cnpmjs git clone https://github.com.cnpmjs.org/H5-Dooring/dooringx.git # or git clone https://github.com/H5-Dooring/dooringx.git # 进入项目目录cd dooringx # 安装依赖yarn install # 启动基础範例yarn start:example # 启动dooringx-lib yarn start # 启动dooringx doc 文档yarn start:doc yarn build # 安裝依賴yarn install # 克隆项目# cnpmjs git clone https://github.com.cnpmjs.org/H5-Dooring/dooringx.git # or git clone https://github.com/H5-Dooring/dooringx.git # 进入项目目录cd dooringx # 安装依赖yarn install # 启动基础範例yarn start:example # 启动dooringx-lib yarn start # 启动dooringx doc 文档yarn start:doc yarn build # 啟動基礎範例yarn start:example # 克隆项目# cnpmjs git clone https://github.com.cnpmjs.org/H5-Dooring/dooringx.git # or git clone https://github.com/H5-Dooring/dooringx.git # 进入项目目录cd dooringx # 安装依赖yarn install # 启动基础範例yarn start:example # 启动dooringx-lib yarn start # 启动dooringx doc 文档yarn start:doc yarn build # 啟動dooringx-lib # 克隆项目# cnpmjs git clone https://github.com.cnpmjs.org/H5-Dooring/dooringx.git # or git clone https://github.com/H5-Dooring/dooringx.git # 进入项目目录cd dooringx # 安装依赖yarn install # 启动基础範例yarn start:example # 启动dooringx-lib yarn start # 启动dooringx doc 文档yarn start:doc yarn build yarn start # 克隆项目# cnpmjs git clone https://github.com.cnpmjs.org/H5-Dooring/dooringx.git # or git clone https://github.com/H5-Dooring/dooringx.git # 进入项目目录cd dooringx # 安装依赖yarn install # 启动基础範例yarn start:example # 启动dooringx-lib yarn start # 启动dooringx doc 文档yarn start:doc yarn build # 啟動dooringx doc 文檔yarn start:doc # 克隆项目# cnpmjs git clone https://github.com.cnpmjs.org/H5-Dooring/dooringx.git # or git clone https://github.com/H5-Dooring/dooringx.git # 进入项目目录cd dooringx # 安装依赖yarn install # 启动基础範例yarn start:example # 启动dooringx-lib yarn start # 启动dooringx doc 文档yarn start:doc yarn build

demo

blank

github地址:

在了解完使用方式之後,我們來看看基本架構和實現思路。

3.dooringx-lib基礎架構和工作機制

blank

上圖就是我根據目前為了保證框架的靈活性,我們還可以按需安裝對應的功能組件,開發自定義的組件等。如下是一個基本的導入案例:

import { import { RightConfig, Container, useStoreState, innerContainerDragUp, LeftConfig, ContainerWrapper, Control, } from 'dooringx-lib'; RightConfig, import { RightConfig, Container, useStoreState, innerContainerDragUp, LeftConfig, ContainerWrapper, Control, } from 'dooringx-lib'; Container, import { RightConfig, Container, useStoreState, innerContainerDragUp, LeftConfig, ContainerWrapper, Control, } from 'dooringx-lib'; useStoreState, import { RightConfig, Container, useStoreState, innerContainerDragUp, LeftConfig, ContainerWrapper, Control, } from 'dooringx-lib'; innerContainerDragUp, import { RightConfig, Container, useStoreState, innerContainerDragUp, LeftConfig, ContainerWrapper, Control, } from 'dooringx-lib'; LeftConfig, import { RightConfig, Container, useStoreState, innerContainerDragUp, LeftConfig, ContainerWrapper, Control, } from 'dooringx-lib'; ContainerWrapper, import { RightConfig, Container, useStoreState, innerContainerDragUp, LeftConfig, ContainerWrapper, Control, } from 'dooringx-lib'; Control, import { RightConfig, Container, useStoreState, innerContainerDragUp, LeftConfig, ContainerWrapper, Control, } from 'dooringx-lib';

我們將整個框架拆分成了不同的模塊,這些模塊既相互獨立又可以相互關聯。完整的工作流程如下:

blank

由上圖可以看出,我們只需要擁有基礎的業務研發能力,就可以藉助

4.dooringx-lib插件開發

接下來我會和大家分享

4.1 如何導入組件

blank

我們在上圖可以看到左側是我們的組件物料區,分為

const LeftRegistMap: LeftRegistComponentMapItem[] = [ const LeftRegistMap: LeftRegistComponentMapItem[] = [ { type: 'basic', // 组件类别component: 'button', // 组件名称img: 'icon-anniu', // 组件icon displayName: '按钮', // 组件中文名urlFn: () => import('./registComponents/button'), // 注册回调}, ]; { const LeftRegistMap: LeftRegistComponentMapItem[] = [ { type: 'basic', // 组件类别component: 'button', // 组件名称img: 'icon-anniu', // 组件icon displayName: '按钮', // 组件中文名urlFn: () => import('./registComponents/button'), // 注册回调}, ]; type: 'basic', // 組件類別component: 'button', // 組件名稱img: 'icon-anniu', // 組件icon const LeftRegistMap: LeftRegistComponentMapItem[] = [ { type: 'basic', // 组件类别component: 'button', // 组件名称img: 'icon-anniu', // 组件icon displayName: '按钮', // 组件中文名urlFn: () => import('./registComponents/button'), // 注册回调}, ]; displayName: '按鈕', // 組件中文名urlFn: () => import('./registComponents/button'), // 註冊回調}, const LeftRegistMap: LeftRegistComponentMapItem[] = [ { type: 'basic', // 组件类别component: 'button', // 组件名称img: 'icon-anniu', // 组件icon displayName: '按钮', // 组件中文名urlFn: () => import('./registComponents/button'), // 注册回调}, ];

左側組件支持同步導入或者異步導入。

如果需要異步導入組件,則需要填寫也可以支持遠程載入組件,只要

如果需要同步導入組件,則需要將組件放入配置項的

initComponentCache: { initComponentCache: { modalMask: { component: MmodalMask }, }, modalMask: { component: MmodalMask }, initComponentCache: { modalMask: { component: MmodalMask }, },

4.2 如何定制左側面板

blank

左側面板傳入

leftRenderListCategory: [ leftRenderListCategory: [ { type: 'basic', icon: <HighlightOutlined />, displayName: '基础组件', }, { type: 'xxc', icon: <ContainerOutlined />, custom: true, customRender: <div>我是自定义渲染</div>, }, ], { leftRenderListCategory: [ { type: 'basic', icon: <HighlightOutlined />, displayName: '基础组件', }, { type: 'xxc', icon: <ContainerOutlined />, custom: true, customRender: <div>我是自定义渲染</div>, }, ], type: 'basic', leftRenderListCategory: [ { type: 'basic', icon: <HighlightOutlined />, displayName: '基础组件', }, { type: 'xxc', icon: <ContainerOutlined />, custom: true, customRender: <div>我是自定义渲染</div>, }, ], icon: <HighlightOutlined />, leftRenderListCategory: [ { type: 'basic', icon: <HighlightOutlined />, displayName: '基础组件', }, { type: 'xxc', icon: <ContainerOutlined />, custom: true, customRender: <div>我是自定义渲染</div>, }, ], displayName: '基礎組件', leftRenderListCategory: [ { type: 'basic', icon: <HighlightOutlined />, displayName: '基础组件', }, { type: 'xxc', icon: <ContainerOutlined />, custom: true, customRender: <div>我是自定义渲染</div>, }, ], }, leftRenderListCategory: [ { type: 'basic', icon: <HighlightOutlined />, displayName: '基础组件', }, { type: 'xxc', icon: <ContainerOutlined />, custom: true, customRender: <div>我是自定义渲染</div>, }, ], { leftRenderListCategory: [ { type: 'basic', icon: <HighlightOutlined />, displayName: '基础组件', }, { type: 'xxc', icon: <ContainerOutlined />, custom: true, customRender: <div>我是自定义渲染</div>, }, ], type: 'xxc', leftRenderListCategory: [ { type: 'basic', icon: <HighlightOutlined />, displayName: '基础组件', }, { type: 'xxc', icon: <ContainerOutlined />, custom: true, customRender: <div>我是自定义渲染</div>, }, ], icon: <ContainerOutlined />, leftRenderListCategory: [ { type: 'basic', icon: <HighlightOutlined />, displayName: '基础组件', }, { type: 'xxc', icon: <ContainerOutlined />, custom: true, customRender: <div>我是自定义渲染</div>, }, ], custom: true, leftRenderListCategory: [ { type: 'basic', icon: <HighlightOutlined />, displayName: '基础组件', }, { type: 'xxc', icon: <ContainerOutlined />, custom: true, customRender: <div>我是自定义渲染</div>, }, ], customRender: <div>我是自定義渲染</div>, leftRenderListCategory: [ { type: 'basic', icon: <HighlightOutlined />, displayName: '基础组件', }, { type: 'xxc', icon: <ContainerOutlined />, custom: true, customRender: <div>我是自定义渲染</div>, }, ], }, leftRenderListCategory: [ { type: 'basic', icon: <HighlightOutlined />, displayName: '基础组件', }, { type: 'xxc', icon: <ContainerOutlined />, custom: true, customRender: <div>我是自定义渲染</div>, }, ],

type icon當

4.3 開發一個自定義的可視化組件

組件需要導出一個由

const MButton = new ComponentItemFactory( const MButton = new ComponentItemFactory( 'button', '按钮', { style: [ createPannelOptions<FormMap, 'input'>('input', { receive: 'text', label: '文字', }), ], animate: [createPannelOptions<FormMap, 'animateControl'>('animateControl', {})], actions: [createPannelOptions<FormMap, 'actionButton'>('actionButton', {})], }, { props: { ... text:'x.dooring'// input配置项组件接收的初始值}, }, (data, context, store, config) => { return <ButtonTemp data={data} store={store} context={context} config={config}></ButtonTemp>; }, true ); export default MButton; 'button', const MButton = new ComponentItemFactory( 'button', '按钮', { style: [ createPannelOptions<FormMap, 'input'>('input', { receive: 'text', label: '文字', }), ], animate: [createPannelOptions<FormMap, 'animateControl'>('animateControl', {})], actions: [createPannelOptions<FormMap, 'actionButton'>('actionButton', {})], }, { props: { ... text:'x.dooring'// input配置项组件接收的初始值}, }, (data, context, store, config) => { return <ButtonTemp data={data} store={store} context={context} config={config}></ButtonTemp>; }, true ); export default MButton; '按鈕', const MButton = new ComponentItemFactory( 'button', '按钮', { style: [ createPannelOptions<FormMap, 'input'>('input', { receive: 'text', label: '文字', }), ], animate: [createPannelOptions<FormMap, 'animateControl'>('animateControl', {})], actions: [createPannelOptions<FormMap, 'actionButton'>('actionButton', {})], }, { props: { ... text:'x.dooring'// input配置项组件接收的初始值}, }, (data, context, store, config) => { return <ButtonTemp data={data} store={store} context={context} config={config}></ButtonTemp>; }, true ); export default MButton; { const MButton = new ComponentItemFactory( 'button', '按钮', { style: [ createPannelOptions<FormMap, 'input'>('input', { receive: 'text', label: '文字', }), ], animate: [createPannelOptions<FormMap, 'animateControl'>('animateControl', {})], actions: [createPannelOptions<FormMap, 'actionButton'>('actionButton', {})], }, { props: { ... text:'x.dooring'// input配置项组件接收的初始值}, }, (data, context, store, config) => { return <ButtonTemp data={data} store={store} context={context} config={config}></ButtonTemp>; }, true ); export default MButton; style: [ const MButton = new ComponentItemFactory( 'button', '按钮', { style: [ createPannelOptions<FormMap, 'input'>('input', { receive: 'text', label: '文字', }), ], animate: [createPannelOptions<FormMap, 'animateControl'>('animateControl', {})], actions: [createPannelOptions<FormMap, 'actionButton'>('actionButton', {})], }, { props: { ... text:'x.dooring'// input配置项组件接收的初始值}, }, (data, context, store, config) => { return <ButtonTemp data={data} store={store} context={context} config={config}></ButtonTemp>; }, true ); export default MButton; createPannelOptions<FormMap, 'input'>('input', { const MButton = new ComponentItemFactory( 'button', '按钮', { style: [ createPannelOptions<FormMap, 'input'>('input', { receive: 'text', label: '文字', }), ], animate: [createPannelOptions<FormMap, 'animateControl'>('animateControl', {})], actions: [createPannelOptions<FormMap, 'actionButton'>('actionButton', {})], }, { props: { ... text:'x.dooring'// input配置项组件接收的初始值}, }, (data, context, store, config) => { return <ButtonTemp data={data} store={store} context={context} config={config}></ButtonTemp>; }, true ); export default MButton; receive: 'text', const MButton = new ComponentItemFactory( 'button', '按钮', { style: [ createPannelOptions<FormMap, 'input'>('input', { receive: 'text', label: '文字', }), ], animate: [createPannelOptions<FormMap, 'animateControl'>('animateControl', {})], actions: [createPannelOptions<FormMap, 'actionButton'>('actionButton', {})], }, { props: { ... text:'x.dooring'// input配置项组件接收的初始值}, }, (data, context, store, config) => { return <ButtonTemp data={data} store={store} context={context} config={config}></ButtonTemp>; }, true ); export default MButton; label: '文字', const MButton = new ComponentItemFactory( 'button', '按钮', { style: [ createPannelOptions<FormMap, 'input'>('input', { receive: 'text', label: '文字', }), ], animate: [createPannelOptions<FormMap, 'animateControl'>('animateControl', {})], actions: [createPannelOptions<FormMap, 'actionButton'>('actionButton', {})], }, { props: { ... text:'x.dooring'// input配置项组件接收的初始值}, }, (data, context, store, config) => { return <ButtonTemp data={data} store={store} context={context} config={config}></ButtonTemp>; }, true ); export default MButton; }), const MButton = new ComponentItemFactory( 'button', '按钮', { style: [ createPannelOptions<FormMap, 'input'>('input', { receive: 'text', label: '文字', }), ], animate: [createPannelOptions<FormMap, 'animateControl'>('animateControl', {})], actions: [createPannelOptions<FormMap, 'actionButton'>('actionButton', {})], }, { props: { ... text:'x.dooring'// input配置项组件接收的初始值}, }, (data, context, store, config) => { return <ButtonTemp data={data} store={store} context={context} config={config}></ButtonTemp>; }, true ); export default MButton; ], const MButton = new ComponentItemFactory( 'button', '按钮', { style: [ createPannelOptions<FormMap, 'input'>('input', { receive: 'text', label: '文字', }), ], animate: [createPannelOptions<FormMap, 'animateControl'>('animateControl', {})], actions: [createPannelOptions<FormMap, 'actionButton'>('actionButton', {})], }, { props: { ... text:'x.dooring'// input配置项组件接收的初始值}, }, (data, context, store, config) => { return <ButtonTemp data={data} store={store} context={context} config={config}></ButtonTemp>; }, true ); export default MButton; animate: [createPannelOptions<FormMap, 'animateControl'>('animateControl', {})], const MButton = new ComponentItemFactory( 'button', '按钮', { style: [ createPannelOptions<FormMap, 'input'>('input', { receive: 'text', label: '文字', }), ], animate: [createPannelOptions<FormMap, 'animateControl'>('animateControl', {})], actions: [createPannelOptions<FormMap, 'actionButton'>('actionButton', {})], }, { props: { ... text:'x.dooring'// input配置项组件接收的初始值}, }, (data, context, store, config) => { return <ButtonTemp data={data} store={store} context={context} config={config}></ButtonTemp>; }, true ); export default MButton; actions: [createPannelOptions<FormMap, 'actionButton'>('actionButton', {})], const MButton = new ComponentItemFactory( 'button', '按钮', { style: [ createPannelOptions<FormMap, 'input'>('input', { receive: 'text', label: '文字', }), ], animate: [createPannelOptions<FormMap, 'animateControl'>('animateControl', {})], actions: [createPannelOptions<FormMap, 'actionButton'>('actionButton', {})], }, { props: { ... text:'x.dooring'// input配置项组件接收的初始值}, }, (data, context, store, config) => { return <ButtonTemp data={data} store={store} context={context} config={config}></ButtonTemp>; }, true ); export default MButton; }, const MButton = new ComponentItemFactory( 'button', '按钮', { style: [ createPannelOptions<FormMap, 'input'>('input', { receive: 'text', label: '文字', }), ], animate: [createPannelOptions<FormMap, 'animateControl'>('animateControl', {})], actions: [createPannelOptions<FormMap, 'actionButton'>('actionButton', {})], }, { props: { ... text:'x.dooring'// input配置项组件接收的初始值}, }, (data, context, store, config) => { return <ButtonTemp data={data} store={store} context={context} config={config}></ButtonTemp>; }, true ); export default MButton; { const MButton = new ComponentItemFactory( 'button', '按钮', { style: [ createPannelOptions<FormMap, 'input'>('input', { receive: 'text', label: '文字', }), ], animate: [createPannelOptions<FormMap, 'animateControl'>('animateControl', {})], actions: [createPannelOptions<FormMap, 'actionButton'>('actionButton', {})], }, { props: { ... text:'x.dooring'// input配置项组件接收的初始值}, }, (data, context, store, config) => { return <ButtonTemp data={data} store={store} context={context} config={config}></ButtonTemp>; }, true ); export default MButton; props: { const MButton = new ComponentItemFactory( 'button', '按钮', { style: [ createPannelOptions<FormMap, 'input'>('input', { receive: 'text', label: '文字', }), ], animate: [createPannelOptions<FormMap, 'animateControl'>('animateControl', {})], actions: [createPannelOptions<FormMap, 'actionButton'>('actionButton', {})], }, { props: { ... text:'x.dooring'// input配置项组件接收的初始值}, }, (data, context, store, config) => { return <ButtonTemp data={data} store={store} context={context} config={config}></ButtonTemp>; }, true ); export default MButton; ... const MButton = new ComponentItemFactory( 'button', '按钮', { style: [ createPannelOptions<FormMap, 'input'>('input', { receive: 'text', label: '文字', }), ], animate: [createPannelOptions<FormMap, 'animateControl'>('animateControl', {})], actions: [createPannelOptions<FormMap, 'actionButton'>('actionButton', {})], }, { props: { ... text:'x.dooring'// input配置项组件接收的初始值}, }, (data, context, store, config) => { return <ButtonTemp data={data} store={store} context={context} config={config}></ButtonTemp>; }, true ); export default MButton; text:'x.dooring'// input配置項組件接收的初始值}, const MButton = new ComponentItemFactory( 'button', '按钮', { style: [ createPannelOptions<FormMap, 'input'>('input', { receive: 'text', label: '文字', }), ], animate: [createPannelOptions<FormMap, 'animateControl'>('animateControl', {})], actions: [createPannelOptions<FormMap, 'actionButton'>('actionButton', {})], }, { props: { ... text:'x.dooring'// input配置项组件接收的初始值}, }, (data, context, store, config) => { return <ButtonTemp data={data} store={store} context={context} config={config}></ButtonTemp>; }, true ); export default MButton; }, const MButton = new ComponentItemFactory( 'button', '按钮', { style: [ createPannelOptions<FormMap, 'input'>('input', { receive: 'text', label: '文字', }), ], animate: [createPannelOptions<FormMap, 'animateControl'>('animateControl', {})], actions: [createPannelOptions<FormMap, 'actionButton'>('actionButton', {})], }, { props: { ... text:'x.dooring'// input配置项组件接收的初始值}, }, (data, context, store, config) => { return <ButtonTemp data={data} store={store} context={context} config={config}></ButtonTemp>; }, true ); export default MButton; (data, context, store, config) => { const MButton = new ComponentItemFactory( 'button', '按钮', { style: [ createPannelOptions<FormMap, 'input'>('input', { receive: 'text', label: '文字', }), ], animate: [createPannelOptions<FormMap, 'animateControl'>('animateControl', {})], actions: [createPannelOptions<FormMap, 'actionButton'>('actionButton', {})], }, { props: { ... text:'x.dooring'// input配置项组件接收的初始值}, }, (data, context, store, config) => { return <ButtonTemp data={data} store={store} context={context} config={config}></ButtonTemp>; }, true ); export default MButton; return <ButtonTemp data={data} store={store} context={context} config={config}></ButtonTemp>; const MButton = new ComponentItemFactory( 'button', '按钮', { style: [ createPannelOptions<FormMap, 'input'>('input', { receive: 'text', label: '文字', }), ], animate: [createPannelOptions<FormMap, 'animateControl'>('animateControl', {})], actions: [createPannelOptions<FormMap, 'actionButton'>('actionButton', {})], }, { props: { ... text:'x.dooring'// input配置项组件接收的初始值}, }, (data, context, store, config) => { return <ButtonTemp data={data} store={store} context={context} config={config}></ButtonTemp>; }, true ); export default MButton; }, const MButton = new ComponentItemFactory( 'button', '按钮', { style: [ createPannelOptions<FormMap, 'input'>('input', { receive: 'text', label: '文字', }), ], animate: [createPannelOptions<FormMap, 'animateControl'>('animateControl', {})], actions: [createPannelOptions<FormMap, 'actionButton'>('actionButton', {})], }, { props: { ... text:'x.dooring'// input配置项组件接收的初始值}, }, (data, context, store, config) => { return <ButtonTemp data={data} store={store} context={context} config={config}></ButtonTemp>; }, true ); export default MButton; true const MButton = new ComponentItemFactory( 'button', '按钮', { style: [ createPannelOptions<FormMap, 'input'>('input', { receive: 'text', label: '文字', }), ], animate: [createPannelOptions<FormMap, 'animateControl'>('animateControl', {})], actions: [createPannelOptions<FormMap, 'actionButton'>('actionButton', {})], }, { props: { ... text:'x.dooring'// input配置项组件接收的初始值}, }, (data, context, store, config) => { return <ButtonTemp data={data} store={store} context={context} config={config}></ButtonTemp>; }, true ); export default MButton; ); const MButton = new ComponentItemFactory( 'button', '按钮', { style: [ createPannelOptions<FormMap, 'input'>('input', { receive: 'text', label: '文字', }), ], animate: [createPannelOptions<FormMap, 'animateControl'>('animateControl', {})], actions: [createPannelOptions<FormMap, 'actionButton'>('actionButton', {})], }, { props: { ... text:'x.dooring'// input配置项组件接收的初始值}, }, (data, context, store, config) => { return <ButtonTemp data={data} store={store} context={context} config={config}></ButtonTemp>; }, true ); export default MButton;

其中第一個參數為組件註冊名,第二個參數用來展示使用。

第三個參數用來配置右側面板的配置項組件。其中鍵為右側面板的分類,值為配置項組件數組。

第四個參數會配置組件的初始值,特別注意的是,製作組件必須要有初始寬度高度(非由內容撐開),否則會在適配時全選時產生問題。

這個初始值裡有很多有用的屬性,比如fixed代表使用固定定位,可以結合配置項更改該值,使得組件可以fixed定位。

還有

初始值裡的(0.7.0版本開始支持)

第五個參數是個函數,你將獲得配置項中的

context

config

第六個參數

第七個參數

4.4 事件註冊

blank
  1. 註冊時機

事件可以細分為

useDynamicAddEventCenter(pr, ${pr.data.id}-init, '初始渲染時機'); //註冊名必須帶id 約定! useDynamicAddEventCenter(pr, ${pr.data.id}-init, '初始渲染时机'); //注册名必须带id 约定! useDynamicAddEventCenter(pr, ${pr.data.id}-click, '点击执行时机');

useDynamicAddEventCenter第二個參數是註冊的時機名,必須跟

註冊完時機後,我們需要將時機放入對應的觸發位置上,比如這個

<Button <Button onClick={() => { eventCenter.runEventQueue(${pr.data.id}-click, pr.config); }} > x.dooring </Button> onClick={() => { <Button onClick={() => { eventCenter.runEventQueue(${pr.data.id}-click, pr.config); }} > x.dooring </Button> eventCenter.runEventQueue(${pr.data.id}-click, pr.config); <Button onClick={() => { eventCenter.runEventQueue(${pr.data.id}-click, pr.config); }} > x.dooring </Button> }} <Button onClick={() => { eventCenter.runEventQueue(${pr.data.id}-click, pr.config); }} > x.dooring </Button> > <Button onClick={() => { eventCenter.runEventQueue(${pr.data.id}-click, pr.config); }} > x.dooring </Button> x.dooring <Button onClick={() => { eventCenter.runEventQueue(${pr.data.id}-click, pr.config); }} > x.dooring </Button>

其中第一個參數則為註冊的時機名,第二個為

  1. 函數註冊

函數由組件拋出,可以加載到事件鏈上。比如,註冊個改變文本函數,那麼我可以在任意組件的時機中去調用該函數,從而觸發該組件改變文本。

函數註冊需要放入否則會導致函數越來越多。

useEffect(() => { useEffect(() => { const functionCenter = eventCenter.getFunctionCenter(); const unregist = functionCenter.register( ${pr.data.id}+改变文本函数, async (ctx, next, config, args, _eventList, iname) => { const userSelect = iname.data; const ctxVal = changeUserValue( userSelect['改变文本数据源'], args, '_changeval', config, ctx ); const text = ctxVal[0]; setText(text); next(); }, [ { name: '改变文本数据源', data: ['ctx', 'input', 'dataSource'], options: { receive: '_changeval', multi: false, }, }, ] ); return () => { unregist(); }; }, []); const functionCenter = eventCenter.getFunctionCenter(); useEffect(() => { const functionCenter = eventCenter.getFunctionCenter(); const unregist = functionCenter.register( ${pr.data.id}+改变文本函数, async (ctx, next, config, args, _eventList, iname) => { const userSelect = iname.data; const ctxVal = changeUserValue( userSelect['改变文本数据源'], args, '_changeval', config, ctx ); const text = ctxVal[0]; setText(text); next(); }, [ { name: '改变文本数据源', data: ['ctx', 'input', 'dataSource'], options: { receive: '_changeval', multi: false, }, }, ] ); return () => { unregist(); }; }, []); const unregist = functionCenter.register( useEffect(() => { const functionCenter = eventCenter.getFunctionCenter(); const unregist = functionCenter.register( ${pr.data.id}+改变文本函数, async (ctx, next, config, args, _eventList, iname) => { const userSelect = iname.data; const ctxVal = changeUserValue( userSelect['改变文本数据源'], args, '_changeval', config, ctx ); const text = ctxVal[0]; setText(text); next(); }, [ { name: '改变文本数据源', data: ['ctx', 'input', 'dataSource'], options: { receive: '_changeval', multi: false, }, }, ] ); return () => { unregist(); }; }, []); ${pr.data.id}+改變文本函數, useEffect(() => { const functionCenter = eventCenter.getFunctionCenter(); const unregist = functionCenter.register( ${pr.data.id}+改变文本函数, async (ctx, next, config, args, _eventList, iname) => { const userSelect = iname.data; const ctxVal = changeUserValue( userSelect['改变文本数据源'], args, '_changeval', config, ctx ); const text = ctxVal[0]; setText(text); next(); }, [ { name: '改变文本数据源', data: ['ctx', 'input', 'dataSource'], options: { receive: '_changeval', multi: false, }, }, ] ); return () => { unregist(); }; }, []); async (ctx, next, config, args, _eventList, iname) => { useEffect(() => { const functionCenter = eventCenter.getFunctionCenter(); const unregist = functionCenter.register( ${pr.data.id}+改变文本函数, async (ctx, next, config, args, _eventList, iname) => { const userSelect = iname.data; const ctxVal = changeUserValue( userSelect['改变文本数据源'], args, '_changeval', config, ctx ); const text = ctxVal[0]; setText(text); next(); }, [ { name: '改变文本数据源', data: ['ctx', 'input', 'dataSource'], options: { receive: '_changeval', multi: false, }, }, ] ); return () => { unregist(); }; }, []); const userSelect = iname.data; useEffect(() => { const functionCenter = eventCenter.getFunctionCenter(); const unregist = functionCenter.register( ${pr.data.id}+改变文本函数, async (ctx, next, config, args, _eventList, iname) => { const userSelect = iname.data; const ctxVal = changeUserValue( userSelect['改变文本数据源'], args, '_changeval', config, ctx ); const text = ctxVal[0]; setText(text); next(); }, [ { name: '改变文本数据源', data: ['ctx', 'input', 'dataSource'], options: { receive: '_changeval', multi: false, }, }, ] ); return () => { unregist(); }; }, []); const ctxVal = changeUserValue( useEffect(() => { const functionCenter = eventCenter.getFunctionCenter(); const unregist = functionCenter.register( ${pr.data.id}+改变文本函数, async (ctx, next, config, args, _eventList, iname) => { const userSelect = iname.data; const ctxVal = changeUserValue( userSelect['改变文本数据源'], args, '_changeval', config, ctx ); const text = ctxVal[0]; setText(text); next(); }, [ { name: '改变文本数据源', data: ['ctx', 'input', 'dataSource'], options: { receive: '_changeval', multi: false, }, }, ] ); return () => { unregist(); }; }, []); userSelect['改變文本數據源'], useEffect(() => { const functionCenter = eventCenter.getFunctionCenter(); const unregist = functionCenter.register( ${pr.data.id}+改变文本函数, async (ctx, next, config, args, _eventList, iname) => { const userSelect = iname.data; const ctxVal = changeUserValue( userSelect['改变文本数据源'], args, '_changeval', config, ctx ); const text = ctxVal[0]; setText(text); next(); }, [ { name: '改变文本数据源', data: ['ctx', 'input', 'dataSource'], options: { receive: '_changeval', multi: false, }, }, ] ); return () => { unregist(); }; }, []); args, useEffect(() => { const functionCenter = eventCenter.getFunctionCenter(); const unregist = functionCenter.register( ${pr.data.id}+改变文本函数, async (ctx, next, config, args, _eventList, iname) => { const userSelect = iname.data; const ctxVal = changeUserValue( userSelect['改变文本数据源'], args, '_changeval', config, ctx ); const text = ctxVal[0]; setText(text); next(); }, [ { name: '改变文本数据源', data: ['ctx', 'input', 'dataSource'], options: { receive: '_changeval', multi: false, }, }, ] ); return () => { unregist(); }; }, []); '_changeval', useEffect(() => { const functionCenter = eventCenter.getFunctionCenter(); const unregist = functionCenter.register( ${pr.data.id}+改变文本函数, async (ctx, next, config, args, _eventList, iname) => { const userSelect = iname.data; const ctxVal = changeUserValue( userSelect['改变文本数据源'], args, '_changeval', config, ctx ); const text = ctxVal[0]; setText(text); next(); }, [ { name: '改变文本数据源', data: ['ctx', 'input', 'dataSource'], options: { receive: '_changeval', multi: false, }, }, ] ); return () => { unregist(); }; }, []); config, useEffect(() => { const functionCenter = eventCenter.getFunctionCenter(); const unregist = functionCenter.register( ${pr.data.id}+改变文本函数, async (ctx, next, config, args, _eventList, iname) => { const userSelect = iname.data; const ctxVal = changeUserValue( userSelect['改变文本数据源'], args, '_changeval', config, ctx ); const text = ctxVal[0]; setText(text); next(); }, [ { name: '改变文本数据源', data: ['ctx', 'input', 'dataSource'], options: { receive: '_changeval', multi: false, }, }, ] ); return () => { unregist(); }; }, []); ctx useEffect(() => { const functionCenter = eventCenter.getFunctionCenter(); const unregist = functionCenter.register( ${pr.data.id}+改变文本函数, async (ctx, next, config, args, _eventList, iname) => { const userSelect = iname.data; const ctxVal = changeUserValue( userSelect['改变文本数据源'], args, '_changeval', config, ctx ); const text = ctxVal[0]; setText(text); next(); }, [ { name: '改变文本数据源', data: ['ctx', 'input', 'dataSource'], options: { receive: '_changeval', multi: false, }, }, ] ); return () => { unregist(); }; }, []); ); useEffect(() => { const functionCenter = eventCenter.getFunctionCenter(); const unregist = functionCenter.register( ${pr.data.id}+改变文本函数, async (ctx, next, config, args, _eventList, iname) => { const userSelect = iname.data; const ctxVal = changeUserValue( userSelect['改变文本数据源'], args, '_changeval', config, ctx ); const text = ctxVal[0]; setText(text); next(); }, [ { name: '改变文本数据源', data: ['ctx', 'input', 'dataSource'], options: { receive: '_changeval', multi: false, }, }, ] ); return () => { unregist(); }; }, []); const text = ctxVal[0]; useEffect(() => { const functionCenter = eventCenter.getFunctionCenter(); const unregist = functionCenter.register( ${pr.data.id}+改变文本函数, async (ctx, next, config, args, _eventList, iname) => { const userSelect = iname.data; const ctxVal = changeUserValue( userSelect['改变文本数据源'], args, '_changeval', config, ctx ); const text = ctxVal[0]; setText(text); next(); }, [ { name: '改变文本数据源', data: ['ctx', 'input', 'dataSource'], options: { receive: '_changeval', multi: false, }, }, ] ); return () => { unregist(); }; }, []); setText(text); useEffect(() => { const functionCenter = eventCenter.getFunctionCenter(); const unregist = functionCenter.register( ${pr.data.id}+改变文本函数, async (ctx, next, config, args, _eventList, iname) => { const userSelect = iname.data; const ctxVal = changeUserValue( userSelect['改变文本数据源'], args, '_changeval', config, ctx ); const text = ctxVal[0]; setText(text); next(); }, [ { name: '改变文本数据源', data: ['ctx', 'input', 'dataSource'], options: { receive: '_changeval', multi: false, }, }, ] ); return () => { unregist(); }; }, []); next(); useEffect(() => { const functionCenter = eventCenter.getFunctionCenter(); const unregist = functionCenter.register( ${pr.data.id}+改变文本函数, async (ctx, next, config, args, _eventList, iname) => { const userSelect = iname.data; const ctxVal = changeUserValue( userSelect['改变文本数据源'], args, '_changeval', config, ctx ); const text = ctxVal[0]; setText(text); next(); }, [ { name: '改变文本数据源', data: ['ctx', 'input', 'dataSource'], options: { receive: '_changeval', multi: false, }, }, ] ); return () => { unregist(); }; }, []); }, useEffect(() => { const functionCenter = eventCenter.getFunctionCenter(); const unregist = functionCenter.register( ${pr.data.id}+改变文本函数, async (ctx, next, config, args, _eventList, iname) => { const userSelect = iname.data; const ctxVal = changeUserValue( userSelect['改变文本数据源'], args, '_changeval', config, ctx ); const text = ctxVal[0]; setText(text); next(); }, [ { name: '改变文本数据源', data: ['ctx', 'input', 'dataSource'], options: { receive: '_changeval', multi: false, }, }, ] ); return () => { unregist(); }; }, []); [ useEffect(() => { const functionCenter = eventCenter.getFunctionCenter(); const unregist = functionCenter.register( ${pr.data.id}+改变文本函数, async (ctx, next, config, args, _eventList, iname) => { const userSelect = iname.data; const ctxVal = changeUserValue( userSelect['改变文本数据源'], args, '_changeval', config, ctx ); const text = ctxVal[0]; setText(text); next(); }, [ { name: '改变文本数据源', data: ['ctx', 'input', 'dataSource'], options: { receive: '_changeval', multi: false, }, }, ] ); return () => { unregist(); }; }, []); { useEffect(() => { const functionCenter = eventCenter.getFunctionCenter(); const unregist = functionCenter.register( ${pr.data.id}+改变文本函数, async (ctx, next, config, args, _eventList, iname) => { const userSelect = iname.data; const ctxVal = changeUserValue( userSelect['改变文本数据源'], args, '_changeval', config, ctx ); const text = ctxVal[0]; setText(text); next(); }, [ { name: '改变文本数据源', data: ['ctx', 'input', 'dataSource'], options: { receive: '_changeval', multi: false, }, }, ] ); return () => { unregist(); }; }, []); name: '改變文本數據源', useEffect(() => { const functionCenter = eventCenter.getFunctionCenter(); const unregist = functionCenter.register( ${pr.data.id}+改变文本函数, async (ctx, next, config, args, _eventList, iname) => { const userSelect = iname.data; const ctxVal = changeUserValue( userSelect['改变文本数据源'], args, '_changeval', config, ctx ); const text = ctxVal[0]; setText(text); next(); }, [ { name: '改变文本数据源', data: ['ctx', 'input', 'dataSource'], options: { receive: '_changeval', multi: false, }, }, ] ); return () => { unregist(); }; }, []); data: ['ctx', 'input', 'dataSource'], useEffect(() => { const functionCenter = eventCenter.getFunctionCenter(); const unregist = functionCenter.register( ${pr.data.id}+改变文本函数, async (ctx, next, config, args, _eventList, iname) => { const userSelect = iname.data; const ctxVal = changeUserValue( userSelect['改变文本数据源'], args, '_changeval', config, ctx ); const text = ctxVal[0]; setText(text); next(); }, [ { name: '改变文本数据源', data: ['ctx', 'input', 'dataSource'], options: { receive: '_changeval', multi: false, }, }, ] ); return () => { unregist(); }; }, []); options: { useEffect(() => { const functionCenter = eventCenter.getFunctionCenter(); const unregist = functionCenter.register( ${pr.data.id}+改变文本函数, async (ctx, next, config, args, _eventList, iname) => { const userSelect = iname.data; const ctxVal = changeUserValue( userSelect['改变文本数据源'], args, '_changeval', config, ctx ); const text = ctxVal[0]; setText(text); next(); }, [ { name: '改变文本数据源', data: ['ctx', 'input', 'dataSource'], options: { receive: '_changeval', multi: false, }, }, ] ); return () => { unregist(); }; }, []); receive: '_changeval', useEffect(() => { const functionCenter = eventCenter.getFunctionCenter(); const unregist = functionCenter.register( ${pr.data.id}+改变文本函数, async (ctx, next, config, args, _eventList, iname) => { const userSelect = iname.data; const ctxVal = changeUserValue( userSelect['改变文本数据源'], args, '_changeval', config, ctx ); const text = ctxVal[0]; setText(text); next(); }, [ { name: '改变文本数据源', data: ['ctx', 'input', 'dataSource'], options: { receive: '_changeval', multi: false, }, }, ] ); return () => { unregist(); }; }, []); multi: false, useEffect(() => { const functionCenter = eventCenter.getFunctionCenter(); const unregist = functionCenter.register( ${pr.data.id}+改变文本函数, async (ctx, next, config, args, _eventList, iname) => { const userSelect = iname.data; const ctxVal = changeUserValue( userSelect['改变文本数据源'], args, '_changeval', config, ctx ); const text = ctxVal[0]; setText(text); next(); }, [ { name: '改变文本数据源', data: ['ctx', 'input', 'dataSource'], options: { receive: '_changeval', multi: false, }, }, ] ); return () => { unregist(); }; }, []); }, useEffect(() => { const functionCenter = eventCenter.getFunctionCenter(); const unregist = functionCenter.register( ${pr.data.id}+改变文本函数, async (ctx, next, config, args, _eventList, iname) => { const userSelect = iname.data; const ctxVal = changeUserValue( userSelect['改变文本数据源'], args, '_changeval', config, ctx ); const text = ctxVal[0]; setText(text); next(); }, [ { name: '改变文本数据源', data: ['ctx', 'input', 'dataSource'], options: { receive: '_changeval', multi: false, }, }, ] ); return () => { unregist(); }; }, []); }, useEffect(() => { const functionCenter = eventCenter.getFunctionCenter(); const unregist = functionCenter.register( ${pr.data.id}+改变文本函数, async (ctx, next, config, args, _eventList, iname) => { const userSelect = iname.data; const ctxVal = changeUserValue( userSelect['改变文本数据源'], args, '_changeval', config, ctx ); const text = ctxVal[0]; setText(text); next(); }, [ { name: '改变文本数据源', data: ['ctx', 'input', 'dataSource'], options: { receive: '_changeval', multi: false, }, }, ] ); return () => { unregist(); }; }, []); ] useEffect(() => { const functionCenter = eventCenter.getFunctionCenter(); const unregist = functionCenter.register( ${pr.data.id}+改变文本函数, async (ctx, next, config, args, _eventList, iname) => { const userSelect = iname.data; const ctxVal = changeUserValue( userSelect['改变文本数据源'], args, '_changeval', config, ctx ); const text = ctxVal[0]; setText(text); next(); }, [ { name: '改变文本数据源', data: ['ctx', 'input', 'dataSource'], options: { receive: '_changeval', multi: false, }, }, ] ); return () => { unregist(); }; }, []); ); useEffect(() => { const functionCenter = eventCenter.getFunctionCenter(); const unregist = functionCenter.register( ${pr.data.id}+改变文本函数, async (ctx, next, config, args, _eventList, iname) => { const userSelect = iname.data; const ctxVal = changeUserValue( userSelect['改变文本数据源'], args, '_changeval', config, ctx ); const text = ctxVal[0]; setText(text); next(); }, [ { name: '改变文本数据源', data: ['ctx', 'input', 'dataSource'], options: { receive: '_changeval', multi: false, }, }, ] ); return () => { unregist(); }; }, []); return () => { useEffect(() => { const functionCenter = eventCenter.getFunctionCenter(); const unregist = functionCenter.register( ${pr.data.id}+改变文本函数, async (ctx, next, config, args, _eventList, iname) => { const userSelect = iname.data; const ctxVal = changeUserValue( userSelect['改变文本数据源'], args, '_changeval', config, ctx ); const text = ctxVal[0]; setText(text); next(); }, [ { name: '改变文本数据源', data: ['ctx', 'input', 'dataSource'], options: { receive: '_changeval', multi: false, }, }, ] ); return () => { unregist(); }; }, []); unregist(); useEffect(() => { const functionCenter = eventCenter.getFunctionCenter(); const unregist = functionCenter.register( ${pr.data.id}+改变文本函数, async (ctx, next, config, args, _eventList, iname) => { const userSelect = iname.data; const ctxVal = changeUserValue( userSelect['改变文本数据源'], args, '_changeval', config, ctx ); const text = ctxVal[0]; setText(text); next(); }, [ { name: '改变文本数据源', data: ['ctx', 'input', 'dataSource'], options: { receive: '_changeval', multi: false, }, }, ] ); return () => { unregist(); }; }, []); }; useEffect(() => { const functionCenter = eventCenter.getFunctionCenter(); const unregist = functionCenter.register( ${pr.data.id}+改变文本函数, async (ctx, next, config, args, _eventList, iname) => { const userSelect = iname.data; const ctxVal = changeUserValue( userSelect['改变文本数据源'], args, '_changeval', config, ctx ); const text = ctxVal[0]; setText(text); next(); }, [ { name: '改变文本数据源', data: ['ctx', 'input', 'dataSource'], options: { receive: '_changeval', multi: false, }, }, ] ); return () => { unregist(); }; }, []);

函數中參數與配置見後面的函數開發。

4.5 右側面板開發

blank

為了開發自定義的右側屬性面板,我們只要將開發的組件配成一個對象放入為了良好的開發體驗,需要定義個

export interface FormBaseType { export interface FormBaseType { receive?: string; } export interface FormInputType extends FormBaseType { label: string; } export interface FormActionButtonType {} export interface FormAnimateControlType {} export interface FormMap { input: FormInputType; actionButton: FormActionButtonType; animateControl: FormAnimateControlType; } receive?: string; export interface FormBaseType { receive?: string; } export interface FormInputType extends FormBaseType { label: string; } export interface FormActionButtonType {} export interface FormAnimateControlType {} export interface FormMap { input: FormInputType; actionButton: FormActionButtonType; animateControl: FormAnimateControlType; } } export interface FormBaseType { receive?: string; } export interface FormInputType extends FormBaseType { label: string; } export interface FormActionButtonType {} export interface FormAnimateControlType {} export interface FormMap { input: FormInputType; actionButton: FormActionButtonType; animateControl: FormAnimateControlType; } export interface FormInputType extends FormBaseType { export interface FormBaseType { receive?: string; } export interface FormInputType extends FormBaseType { label: string; } export interface FormActionButtonType {} export interface FormAnimateControlType {} export interface FormMap { input: FormInputType; actionButton: FormActionButtonType; animateControl: FormAnimateControlType; } label: string; export interface FormBaseType { receive?: string; } export interface FormInputType extends FormBaseType { label: string; } export interface FormActionButtonType {} export interface FormAnimateControlType {} export interface FormMap { input: FormInputType; actionButton: FormActionButtonType; animateControl: FormAnimateControlType; } } export interface FormBaseType { receive?: string; } export interface FormInputType extends FormBaseType { label: string; } export interface FormActionButtonType {} export interface FormAnimateControlType {} export interface FormMap { input: FormInputType; actionButton: FormActionButtonType; animateControl: FormAnimateControlType; } export interface FormActionButtonType {} export interface FormBaseType { receive?: string; } export interface FormInputType extends FormBaseType { label: string; } export interface FormActionButtonType {} export interface FormAnimateControlType {} export interface FormMap { input: FormInputType; actionButton: FormActionButtonType; animateControl: FormAnimateControlType; } export interface FormAnimateControlType {} export interface FormBaseType { receive?: string; } export interface FormInputType extends FormBaseType { label: string; } export interface FormActionButtonType {} export interface FormAnimateControlType {} export interface FormMap { input: FormInputType; actionButton: FormActionButtonType; animateControl: FormAnimateControlType; } export interface FormMap { export interface FormBaseType { receive?: string; } export interface FormInputType extends FormBaseType { label: string; } export interface FormActionButtonType {} export interface FormAnimateControlType {} export interface FormMap { input: FormInputType; actionButton: FormActionButtonType; animateControl: FormAnimateControlType; } input: FormInputType; export interface FormBaseType { receive?: string; } export interface FormInputType extends FormBaseType { label: string; } export interface FormActionButtonType {} export interface FormAnimateControlType {} export interface FormMap { input: FormInputType; actionButton: FormActionButtonType; animateControl: FormAnimateControlType; } actionButton: FormActionButtonType; export interface FormBaseType { receive?: string; } export interface FormInputType extends FormBaseType { label: string; } export interface FormActionButtonType {} export interface FormAnimateControlType {} export interface FormMap { input: FormInputType; actionButton: FormActionButtonType; animateControl: FormAnimateControlType; } animateControl: FormAnimateControlType; export interface FormBaseType { receive?: string; } export interface FormInputType extends FormBaseType { label: string; } export interface FormActionButtonType {} export interface FormAnimateControlType {} export interface FormMap { input: FormInputType; actionButton: FormActionButtonType; animateControl: FormAnimateControlType; }

formMap

那麼在開發該組件時,

interface MInputProps { interface MInputProps { data: CreateOptionsRes<FormMap, 'input'>; current: IBlockType; config: UserConfig; } data: CreateOptionsRes<FormMap, 'input'>; interface MInputProps { data: CreateOptionsRes<FormMap, 'input'>; current: IBlockType; config: UserConfig; } current: IBlockType; interface MInputProps { data: CreateOptionsRes<FormMap, 'input'>; current: IBlockType; config: UserConfig; } config: UserConfig; interface MInputProps { data: CreateOptionsRes<FormMap, 'input'>; current: IBlockType; config: UserConfig; }

也就是

還記得在左側組件開發中的第三個參數嗎?這樣就都關聯起來了:

style: [ style: [ createPannelOptions<FormMap, 'input'>('input', { receive: 'text', label: '文字' }) ], createPannelOptions<FormMap, 'input'>('input', { style: [ createPannelOptions<FormMap, 'input'>('input', { receive: 'text', label: '文字' }) ], receive: 'text', style: [ createPannelOptions<FormMap, 'input'>('input', { receive: 'text', label: '文字' }) ], label: '文字' style: [ createPannelOptions<FormMap, 'input'>('input', { receive: 'text', label: '文字' }) ], }) style: [ createPannelOptions<FormMap, 'input'>('input', { receive: 'text', label: '文字' }) ],

createPannelOptions

在配置項組件裡所要做的就是接收組件傳來的配置項,然後去修改

function MInput(props: MInputProps) { function MInput(props: MInputProps) { const option = useMemo(() => { return props.data?.option || {}; }, [props.data]); return ( <Row style={{ padding: '10px 20px' }}> <Col span={6} style={{ lineHeight: '30px' }}> {(option as any)?.label || '文字'}: </Col> <Col span={18}> <Input value={props.current.props[(option as any).receive] || ''} onChange={(e) => { const receive = (option as any).receive; const clonedata = deepCopy(store.getData()); const newblock = clonedata.block.map((v: IBlockType) => { if (v.id === props.current.id) { v.props[receive] = e.target.value; } return v; }); store.setData({ ...clonedata, block: [...newblock] }); }} ></Input> </Col> </Row> ); } const option = useMemo(() => { function MInput(props: MInputProps) { const option = useMemo(() => { return props.data?.option || {}; }, [props.data]); return ( <Row style={{ padding: '10px 20px' }}> <Col span={6} style={{ lineHeight: '30px' }}> {(option as any)?.label || '文字'}: </Col> <Col span={18}> <Input value={props.current.props[(option as any).receive] || ''} onChange={(e) => { const receive = (option as any).receive; const clonedata = deepCopy(store.getData()); const newblock = clonedata.block.map((v: IBlockType) => { if (v.id === props.current.id) { v.props[receive] = e.target.value; } return v; }); store.setData({ ...clonedata, block: [...newblock] }); }} ></Input> </Col> </Row> ); } return props.data?.option || {}; function MInput(props: MInputProps) { const option = useMemo(() => { return props.data?.option || {}; }, [props.data]); return ( <Row style={{ padding: '10px 20px' }}> <Col span={6} style={{ lineHeight: '30px' }}> {(option as any)?.label || '文字'}: </Col> <Col span={18}> <Input value={props.current.props[(option as any).receive] || ''} onChange={(e) => { const receive = (option as any).receive; const clonedata = deepCopy(store.getData()); const newblock = clonedata.block.map((v: IBlockType) => { if (v.id === props.current.id) { v.props[receive] = e.target.value; } return v; }); store.setData({ ...clonedata, block: [...newblock] }); }} ></Input> </Col> </Row> ); } }, [props.data]); function MInput(props: MInputProps) { const option = useMemo(() => { return props.data?.option || {}; }, [props.data]); return ( <Row style={{ padding: '10px 20px' }}> <Col span={6} style={{ lineHeight: '30px' }}> {(option as any)?.label || '文字'}: </Col> <Col span={18}> <Input value={props.current.props[(option as any).receive] || ''} onChange={(e) => { const receive = (option as any).receive; const clonedata = deepCopy(store.getData()); const newblock = clonedata.block.map((v: IBlockType) => { if (v.id === props.current.id) { v.props[receive] = e.target.value; } return v; }); store.setData({ ...clonedata, block: [...newblock] }); }} ></Input> </Col> </Row> ); } return ( function MInput(props: MInputProps) { const option = useMemo(() => { return props.data?.option || {}; }, [props.data]); return ( <Row style={{ padding: '10px 20px' }}> <Col span={6} style={{ lineHeight: '30px' }}> {(option as any)?.label || '文字'}: </Col> <Col span={18}> <Input value={props.current.props[(option as any).receive] || ''} onChange={(e) => { const receive = (option as any).receive; const clonedata = deepCopy(store.getData()); const newblock = clonedata.block.map((v: IBlockType) => { if (v.id === props.current.id) { v.props[receive] = e.target.value; } return v; }); store.setData({ ...clonedata, block: [...newblock] }); }} ></Input> </Col> </Row> ); } <Row style={{ padding: '10px 20px' }}> function MInput(props: MInputProps) { const option = useMemo(() => { return props.data?.option || {}; }, [props.data]); return ( <Row style={{ padding: '10px 20px' }}> <Col span={6} style={{ lineHeight: '30px' }}> {(option as any)?.label || '文字'}: </Col> <Col span={18}> <Input value={props.current.props[(option as any).receive] || ''} onChange={(e) => { const receive = (option as any).receive; const clonedata = deepCopy(store.getData()); const newblock = clonedata.block.map((v: IBlockType) => { if (v.id === props.current.id) { v.props[receive] = e.target.value; } return v; }); store.setData({ ...clonedata, block: [...newblock] }); }} ></Input> </Col> </Row> ); } <Col span={6} style={{ lineHeight: '30px' }}> function MInput(props: MInputProps) { const option = useMemo(() => { return props.data?.option || {}; }, [props.data]); return ( <Row style={{ padding: '10px 20px' }}> <Col span={6} style={{ lineHeight: '30px' }}> {(option as any)?.label || '文字'}: </Col> <Col span={18}> <Input value={props.current.props[(option as any).receive] || ''} onChange={(e) => { const receive = (option as any).receive; const clonedata = deepCopy(store.getData()); const newblock = clonedata.block.map((v: IBlockType) => { if (v.id === props.current.id) { v.props[receive] = e.target.value; } return v; }); store.setData({ ...clonedata, block: [...newblock] }); }} ></Input> </Col> </Row> ); } {(option as any)?.label || '文字'}: function MInput(props: MInputProps) { const option = useMemo(() => { return props.data?.option || {}; }, [props.data]); return ( <Row style={{ padding: '10px 20px' }}> <Col span={6} style={{ lineHeight: '30px' }}> {(option as any)?.label || '文字'}: </Col> <Col span={18}> <Input value={props.current.props[(option as any).receive] || ''} onChange={(e) => { const receive = (option as any).receive; const clonedata = deepCopy(store.getData()); const newblock = clonedata.block.map((v: IBlockType) => { if (v.id === props.current.id) { v.props[receive] = e.target.value; } return v; }); store.setData({ ...clonedata, block: [...newblock] }); }} ></Input> </Col> </Row> ); } </Col> function MInput(props: MInputProps) { const option = useMemo(() => { return props.data?.option || {}; }, [props.data]); return ( <Row style={{ padding: '10px 20px' }}> <Col span={6} style={{ lineHeight: '30px' }}> {(option as any)?.label || '文字'}: </Col> <Col span={18}> <Input value={props.current.props[(option as any).receive] || ''} onChange={(e) => { const receive = (option as any).receive; const clonedata = deepCopy(store.getData()); const newblock = clonedata.block.map((v: IBlockType) => { if (v.id === props.current.id) { v.props[receive] = e.target.value; } return v; }); store.setData({ ...clonedata, block: [...newblock] }); }} ></Input> </Col> </Row> ); } <Col span={18}> function MInput(props: MInputProps) { const option = useMemo(() => { return props.data?.option || {}; }, [props.data]); return ( <Row style={{ padding: '10px 20px' }}> <Col span={6} style={{ lineHeight: '30px' }}> {(option as any)?.label || '文字'}: </Col> <Col span={18}> <Input value={props.current.props[(option as any).receive] || ''} onChange={(e) => { const receive = (option as any).receive; const clonedata = deepCopy(store.getData()); const newblock = clonedata.block.map((v: IBlockType) => { if (v.id === props.current.id) { v.props[receive] = e.target.value; } return v; }); store.setData({ ...clonedata, block: [...newblock] }); }} ></Input> </Col> </Row> ); } <Input function MInput(props: MInputProps) { const option = useMemo(() => { return props.data?.option || {}; }, [props.data]); return ( <Row style={{ padding: '10px 20px' }}> <Col span={6} style={{ lineHeight: '30px' }}> {(option as any)?.label || '文字'}: </Col> <Col span={18}> <Input value={props.current.props[(option as any).receive] || ''} onChange={(e) => { const receive = (option as any).receive; const clonedata = deepCopy(store.getData()); const newblock = clonedata.block.map((v: IBlockType) => { if (v.id === props.current.id) { v.props[receive] = e.target.value; } return v; }); store.setData({ ...clonedata, block: [...newblock] }); }} ></Input> </Col> </Row> ); } value={props.current.props[(option as any).receive] || ''} function MInput(props: MInputProps) { const option = useMemo(() => { return props.data?.option || {}; }, [props.data]); return ( <Row style={{ padding: '10px 20px' }}> <Col span={6} style={{ lineHeight: '30px' }}> {(option as any)?.label || '文字'}: </Col> <Col span={18}> <Input value={props.current.props[(option as any).receive] || ''} onChange={(e) => { const receive = (option as any).receive; const clonedata = deepCopy(store.getData()); const newblock = clonedata.block.map((v: IBlockType) => { if (v.id === props.current.id) { v.props[receive] = e.target.value; } return v; }); store.setData({ ...clonedata, block: [...newblock] }); }} ></Input> </Col> </Row> ); } onChange={(e) => { function MInput(props: MInputProps) { const option = useMemo(() => { return props.data?.option || {}; }, [props.data]); return ( <Row style={{ padding: '10px 20px' }}> <Col span={6} style={{ lineHeight: '30px' }}> {(option as any)?.label || '文字'}: </Col> <Col span={18}> <Input value={props.current.props[(option as any).receive] || ''} onChange={(e) => { const receive = (option as any).receive; const clonedata = deepCopy(store.getData()); const newblock = clonedata.block.map((v: IBlockType) => { if (v.id === props.current.id) { v.props[receive] = e.target.value; } return v; }); store.setData({ ...clonedata, block: [...newblock] }); }} ></Input> </Col> </Row> ); } const receive = (option as any).receive; function MInput(props: MInputProps) { const option = useMemo(() => { return props.data?.option || {}; }, [props.data]); return ( <Row style={{ padding: '10px 20px' }}> <Col span={6} style={{ lineHeight: '30px' }}> {(option as any)?.label || '文字'}: </Col> <Col span={18}> <Input value={props.current.props[(option as any).receive] || ''} onChange={(e) => { const receive = (option as any).receive; const clonedata = deepCopy(store.getData()); const newblock = clonedata.block.map((v: IBlockType) => { if (v.id === props.current.id) { v.props[receive] = e.target.value; } return v; }); store.setData({ ...clonedata, block: [...newblock] }); }} ></Input> </Col> </Row> ); } const clonedata = deepCopy(store.getData()); function MInput(props: MInputProps) { const option = useMemo(() => { return props.data?.option || {}; }, [props.data]); return ( <Row style={{ padding: '10px 20px' }}> <Col span={6} style={{ lineHeight: '30px' }}> {(option as any)?.label || '文字'}: </Col> <Col span={18}> <Input value={props.current.props[(option as any).receive] || ''} onChange={(e) => { const receive = (option as any).receive; const clonedata = deepCopy(store.getData()); const newblock = clonedata.block.map((v: IBlockType) => { if (v.id === props.current.id) { v.props[receive] = e.target.value; } return v; }); store.setData({ ...clonedata, block: [...newblock] }); }} ></Input> </Col> </Row> ); } const newblock = clonedata.block.map((v: IBlockType) => { function MInput(props: MInputProps) { const option = useMemo(() => { return props.data?.option || {}; }, [props.data]); return ( <Row style={{ padding: '10px 20px' }}> <Col span={6} style={{ lineHeight: '30px' }}> {(option as any)?.label || '文字'}: </Col> <Col span={18}> <Input value={props.current.props[(option as any).receive] || ''} onChange={(e) => { const receive = (option as any).receive; const clonedata = deepCopy(store.getData()); const newblock = clonedata.block.map((v: IBlockType) => { if (v.id === props.current.id) { v.props[receive] = e.target.value; } return v; }); store.setData({ ...clonedata, block: [...newblock] }); }} ></Input> </Col> </Row> ); } if (v.id === props.current.id) { function MInput(props: MInputProps) { const option = useMemo(() => { return props.data?.option || {}; }, [props.data]); return ( <Row style={{ padding: '10px 20px' }}> <Col span={6} style={{ lineHeight: '30px' }}> {(option as any)?.label || '文字'}: </Col> <Col span={18}> <Input value={props.current.props[(option as any).receive] || ''} onChange={(e) => { const receive = (option as any).receive; const clonedata = deepCopy(store.getData()); const newblock = clonedata.block.map((v: IBlockType) => { if (v.id === props.current.id) { v.props[receive] = e.target.value; } return v; }); store.setData({ ...clonedata, block: [...newblock] }); }} ></Input> </Col> </Row> ); } v.props[receive] = e.target.value; function MInput(props: MInputProps) { const option = useMemo(() => { return props.data?.option || {}; }, [props.data]); return ( <Row style={{ padding: '10px 20px' }}> <Col span={6} style={{ lineHeight: '30px' }}> {(option as any)?.label || '文字'}: </Col> <Col span={18}> <Input value={props.current.props[(option as any).receive] || ''} onChange={(e) => { const receive = (option as any).receive; const clonedata = deepCopy(store.getData()); const newblock = clonedata.block.map((v: IBlockType) => { if (v.id === props.current.id) { v.props[receive] = e.target.value; } return v; }); store.setData({ ...clonedata, block: [...newblock] }); }} ></Input> </Col> </Row> ); } } function MInput(props: MInputProps) { const option = useMemo(() => { return props.data?.option || {}; }, [props.data]); return ( <Row style={{ padding: '10px 20px' }}> <Col span={6} style={{ lineHeight: '30px' }}> {(option as any)?.label || '文字'}: </Col> <Col span={18}> <Input value={props.current.props[(option as any).receive] || ''} onChange={(e) => { const receive = (option as any).receive; const clonedata = deepCopy(store.getData()); const newblock = clonedata.block.map((v: IBlockType) => { if (v.id === props.current.id) { v.props[receive] = e.target.value; } return v; }); store.setData({ ...clonedata, block: [...newblock] }); }} ></Input> </Col> </Row> ); } return v; function MInput(props: MInputProps) { const option = useMemo(() => { return props.data?.option || {}; }, [props.data]); return ( <Row style={{ padding: '10px 20px' }}> <Col span={6} style={{ lineHeight: '30px' }}> {(option as any)?.label || '文字'}: </Col> <Col span={18}> <Input value={props.current.props[(option as any).receive] || ''} onChange={(e) => { const receive = (option as any).receive; const clonedata = deepCopy(store.getData()); const newblock = clonedata.block.map((v: IBlockType) => { if (v.id === props.current.id) { v.props[receive] = e.target.value; } return v; }); store.setData({ ...clonedata, block: [...newblock] }); }} ></Input> </Col> </Row> ); } }); function MInput(props: MInputProps) { const option = useMemo(() => { return props.data?.option || {}; }, [props.data]); return ( <Row style={{ padding: '10px 20px' }}> <Col span={6} style={{ lineHeight: '30px' }}> {(option as any)?.label || '文字'}: </Col> <Col span={18}> <Input value={props.current.props[(option as any).receive] || ''} onChange={(e) => { const receive = (option as any).receive; const clonedata = deepCopy(store.getData()); const newblock = clonedata.block.map((v: IBlockType) => { if (v.id === props.current.id) { v.props[receive] = e.target.value; } return v; }); store.setData({ ...clonedata, block: [...newblock] }); }} ></Input> </Col> </Row> ); } store.setData({ ...clonedata, block: [...newblock] }); function MInput(props: MInputProps) { const option = useMemo(() => { return props.data?.option || {}; }, [props.data]); return ( <Row style={{ padding: '10px 20px' }}> <Col span={6} style={{ lineHeight: '30px' }}> {(option as any)?.label || '文字'}: </Col> <Col span={18}> <Input value={props.current.props[(option as any).receive] || ''} onChange={(e) => { const receive = (option as any).receive; const clonedata = deepCopy(store.getData()); const newblock = clonedata.block.map((v: IBlockType) => { if (v.id === props.current.id) { v.props[receive] = e.target.value; } return v; }); store.setData({ ...clonedata, block: [...newblock] }); }} ></Input> </Col> </Row> ); } }} function MInput(props: MInputProps) { const option = useMemo(() => { return props.data?.option || {}; }, [props.data]); return ( <Row style={{ padding: '10px 20px' }}> <Col span={6} style={{ lineHeight: '30px' }}> {(option as any)?.label || '文字'}: </Col> <Col span={18}> <Input value={props.current.props[(option as any).receive] || ''} onChange={(e) => { const receive = (option as any).receive; const clonedata = deepCopy(store.getData()); const newblock = clonedata.block.map((v: IBlockType) => { if (v.id === props.current.id) { v.props[receive] = e.target.value; } return v; }); store.setData({ ...clonedata, block: [...newblock] }); }} ></Input> </Col> </Row> ); } ></Input> function MInput(props: MInputProps) { const option = useMemo(() => { return props.data?.option || {}; }, [props.data]); return ( <Row style={{ padding: '10px 20px' }}> <Col span={6} style={{ lineHeight: '30px' }}> {(option as any)?.label || '文字'}: </Col> <Col span={18}> <Input value={props.current.props[(option as any).receive] || ''} onChange={(e) => { const receive = (option as any).receive; const clonedata = deepCopy(store.getData()); const newblock = clonedata.block.map((v: IBlockType) => { if (v.id === props.current.id) { v.props[receive] = e.target.value; } return v; }); store.setData({ ...clonedata, block: [...newblock] }); }} ></Input> </Col> </Row> ); } </Col> function MInput(props: MInputProps) { const option = useMemo(() => { return props.data?.option || {}; }, [props.data]); return ( <Row style={{ padding: '10px 20px' }}> <Col span={6} style={{ lineHeight: '30px' }}> {(option as any)?.label || '文字'}: </Col> <Col span={18}> <Input value={props.current.props[(option as any).receive] || ''} onChange={(e) => { const receive = (option as any).receive; const clonedata = deepCopy(store.getData()); const newblock = clonedata.block.map((v: IBlockType) => { if (v.id === props.current.id) { v.props[receive] = e.target.value; } return v; }); store.setData({ ...clonedata, block: [...newblock] }); }} ></Input> </Col> </Row> ); } </Row> function MInput(props: MInputProps) { const option = useMemo(() => { return props.data?.option || {}; }, [props.data]); return ( <Row style={{ padding: '10px 20px' }}> <Col span={6} style={{ lineHeight: '30px' }}> {(option as any)?.label || '文字'}: </Col> <Col span={18}> <Input value={props.current.props[(option as any).receive] || ''} onChange={(e) => { const receive = (option as any).receive; const clonedata = deepCopy(store.getData()); const newblock = clonedata.block.map((v: IBlockType) => { if (v.id === props.current.id) { v.props[receive] = e.target.value; } return v; }); store.setData({ ...clonedata, block: [...newblock] }); }} ></Input> </Col> </Row> ); } ); function MInput(props: MInputProps) { const option = useMemo(() => { return props.data?.option || {}; }, [props.data]); return ( <Row style={{ padding: '10px 20px' }}> <Col span={6} style={{ lineHeight: '30px' }}> {(option as any)?.label || '文字'}: </Col> <Col span={18}> <Input value={props.current.props[(option as any).receive] || ''} onChange={(e) => { const receive = (option as any).receive; const clonedata = deepCopy(store.getData()); const newblock = clonedata.block.map((v: IBlockType) => { if (v.id === props.current.id) { v.props[receive] = e.target.value; } return v; }); store.setData({ ...clonedata, block: [...newblock] }); }} ></Input> </Col> </Row> ); }

由於可以很輕鬆的拿到

將組件的

注意:如果你的右側組件需要用到

4.6 自定義右鍵菜單

blank

右鍵菜單可以進行自定義:

// 自定義右鍵const contextMenuState = config.getContextMenuState(); // 自定义右键const contextMenuState = config.getContextMenuState(); const unmountContextMenu = contextMenuState.unmountContextMenu; const commander = config.getCommanderRegister(); const ContextMenu = () => { const handleclick = () => { unmountContextMenu(); }; const forceUpdate = useState(0)[1]; contextMenuState.forceUpdate = () => { forceUpdate((pre) => pre + 1); }; return ( <div style={{ left: contextMenuState.left, top: contextMenuState.top, position: 'fixed', background: 'rgb(24, 23, 23)', }} > <div style={{ width: '100%' }} onClick={() => { commander.exec('redo'); handleclick(); }} > <Button>自定义</Button> </div> </div> ); }; contextMenuState.contextMenu = <ContextMenu></ContextMenu>; const unmountContextMenu = contextMenuState.unmountContextMenu; // 自定义右键const contextMenuState = config.getContextMenuState(); const unmountContextMenu = contextMenuState.unmountContextMenu; const commander = config.getCommanderRegister(); const ContextMenu = () => { const handleclick = () => { unmountContextMenu(); }; const forceUpdate = useState(0)[1]; contextMenuState.forceUpdate = () => { forceUpdate((pre) => pre + 1); }; return ( <div style={{ left: contextMenuState.left, top: contextMenuState.top, position: 'fixed', background: 'rgb(24, 23, 23)', }} > <div style={{ width: '100%' }} onClick={() => { commander.exec('redo'); handleclick(); }} > <Button>自定义</Button> </div> </div> ); }; contextMenuState.contextMenu = <ContextMenu></ContextMenu>; const commander = config.getCommanderRegister(); // 自定义右键const contextMenuState = config.getContextMenuState(); const unmountContextMenu = contextMenuState.unmountContextMenu; const commander = config.getCommanderRegister(); const ContextMenu = () => { const handleclick = () => { unmountContextMenu(); }; const forceUpdate = useState(0)[1]; contextMenuState.forceUpdate = () => { forceUpdate((pre) => pre + 1); }; return ( <div style={{ left: contextMenuState.left, top: contextMenuState.top, position: 'fixed', background: 'rgb(24, 23, 23)', }} > <div style={{ width: '100%' }} onClick={() => { commander.exec('redo'); handleclick(); }} > <Button>自定义</Button> </div> </div> ); }; contextMenuState.contextMenu = <ContextMenu></ContextMenu>; const ContextMenu = () => { // 自定义右键const contextMenuState = config.getContextMenuState(); const unmountContextMenu = contextMenuState.unmountContextMenu; const commander = config.getCommanderRegister(); const ContextMenu = () => { const handleclick = () => { unmountContextMenu(); }; const forceUpdate = useState(0)[1]; contextMenuState.forceUpdate = () => { forceUpdate((pre) => pre + 1); }; return ( <div style={{ left: contextMenuState.left, top: contextMenuState.top, position: 'fixed', background: 'rgb(24, 23, 23)', }} > <div style={{ width: '100%' }} onClick={() => { commander.exec('redo'); handleclick(); }} > <Button>自定义</Button> </div> </div> ); }; contextMenuState.contextMenu = <ContextMenu></ContextMenu>; const handleclick = () => { // 自定义右键const contextMenuState = config.getContextMenuState(); const unmountContextMenu = contextMenuState.unmountContextMenu; const commander = config.getCommanderRegister(); const ContextMenu = () => { const handleclick = () => { unmountContextMenu(); }; const forceUpdate = useState(0)[1]; contextMenuState.forceUpdate = () => { forceUpdate((pre) => pre + 1); }; return ( <div style={{ left: contextMenuState.left, top: contextMenuState.top, position: 'fixed', background: 'rgb(24, 23, 23)', }} > <div style={{ width: '100%' }} onClick={() => { commander.exec('redo'); handleclick(); }} > <Button>自定义</Button> </div> </div> ); }; contextMenuState.contextMenu = <ContextMenu></ContextMenu>; unmountContextMenu(); // 自定义右键const contextMenuState = config.getContextMenuState(); const unmountContextMenu = contextMenuState.unmountContextMenu; const commander = config.getCommanderRegister(); const ContextMenu = () => { const handleclick = () => { unmountContextMenu(); }; const forceUpdate = useState(0)[1]; contextMenuState.forceUpdate = () => { forceUpdate((pre) => pre + 1); }; return ( <div style={{ left: contextMenuState.left, top: contextMenuState.top, position: 'fixed', background: 'rgb(24, 23, 23)', }} > <div style={{ width: '100%' }} onClick={() => { commander.exec('redo'); handleclick(); }} > <Button>自定义</Button> </div> </div> ); }; contextMenuState.contextMenu = <ContextMenu></ContextMenu>; }; // 自定义右键const contextMenuState = config.getContextMenuState(); const unmountContextMenu = contextMenuState.unmountContextMenu; const commander = config.getCommanderRegister(); const ContextMenu = () => { const handleclick = () => { unmountContextMenu(); }; const forceUpdate = useState(0)[1]; contextMenuState.forceUpdate = () => { forceUpdate((pre) => pre + 1); }; return ( <div style={{ left: contextMenuState.left, top: contextMenuState.top, position: 'fixed', background: 'rgb(24, 23, 23)', }} > <div style={{ width: '100%' }} onClick={() => { commander.exec('redo'); handleclick(); }} > <Button>自定义</Button> </div> </div> ); }; contextMenuState.contextMenu = <ContextMenu></ContextMenu>; const forceUpdate = useState(0)[1]; // 自定义右键const contextMenuState = config.getContextMenuState(); const unmountContextMenu = contextMenuState.unmountContextMenu; const commander = config.getCommanderRegister(); const ContextMenu = () => { const handleclick = () => { unmountContextMenu(); }; const forceUpdate = useState(0)[1]; contextMenuState.forceUpdate = () => { forceUpdate((pre) => pre + 1); }; return ( <div style={{ left: contextMenuState.left, top: contextMenuState.top, position: 'fixed', background: 'rgb(24, 23, 23)', }} > <div style={{ width: '100%' }} onClick={() => { commander.exec('redo'); handleclick(); }} > <Button>自定义</Button> </div> </div> ); }; contextMenuState.contextMenu = <ContextMenu></ContextMenu>; contextMenuState.forceUpdate = () => { // 自定义右键const contextMenuState = config.getContextMenuState(); const unmountContextMenu = contextMenuState.unmountContextMenu; const commander = config.getCommanderRegister(); const ContextMenu = () => { const handleclick = () => { unmountContextMenu(); }; const forceUpdate = useState(0)[1]; contextMenuState.forceUpdate = () => { forceUpdate((pre) => pre + 1); }; return ( <div style={{ left: contextMenuState.left, top: contextMenuState.top, position: 'fixed', background: 'rgb(24, 23, 23)', }} > <div style={{ width: '100%' }} onClick={() => { commander.exec('redo'); handleclick(); }} > <Button>自定义</Button> </div> </div> ); }; contextMenuState.contextMenu = <ContextMenu></ContextMenu>; forceUpdate((pre) => pre + 1); // 自定义右键const contextMenuState = config.getContextMenuState(); const unmountContextMenu = contextMenuState.unmountContextMenu; const commander = config.getCommanderRegister(); const ContextMenu = () => { const handleclick = () => { unmountContextMenu(); }; const forceUpdate = useState(0)[1]; contextMenuState.forceUpdate = () => { forceUpdate((pre) => pre + 1); }; return ( <div style={{ left: contextMenuState.left, top: contextMenuState.top, position: 'fixed', background: 'rgb(24, 23, 23)', }} > <div style={{ width: '100%' }} onClick={() => { commander.exec('redo'); handleclick(); }} > <Button>自定义</Button> </div> </div> ); }; contextMenuState.contextMenu = <ContextMenu></ContextMenu>; }; // 自定义右键const contextMenuState = config.getContextMenuState(); const unmountContextMenu = contextMenuState.unmountContextMenu; const commander = config.getCommanderRegister(); const ContextMenu = () => { const handleclick = () => { unmountContextMenu(); }; const forceUpdate = useState(0)[1]; contextMenuState.forceUpdate = () => { forceUpdate((pre) => pre + 1); }; return ( <div style={{ left: contextMenuState.left, top: contextMenuState.top, position: 'fixed', background: 'rgb(24, 23, 23)', }} > <div style={{ width: '100%' }} onClick={() => { commander.exec('redo'); handleclick(); }} > <Button>自定义</Button> </div> </div> ); }; contextMenuState.contextMenu = <ContextMenu></ContextMenu>; return ( // 自定义右键const contextMenuState = config.getContextMenuState(); const unmountContextMenu = contextMenuState.unmountContextMenu; const commander = config.getCommanderRegister(); const ContextMenu = () => { const handleclick = () => { unmountContextMenu(); }; const forceUpdate = useState(0)[1]; contextMenuState.forceUpdate = () => { forceUpdate((pre) => pre + 1); }; return ( <div style={{ left: contextMenuState.left, top: contextMenuState.top, position: 'fixed', background: 'rgb(24, 23, 23)', }} > <div style={{ width: '100%' }} onClick={() => { commander.exec('redo'); handleclick(); }} > <Button>自定义</Button> </div> </div> ); }; contextMenuState.contextMenu = <ContextMenu></ContextMenu>; <div // 自定义右键const contextMenuState = config.getContextMenuState(); const unmountContextMenu = contextMenuState.unmountContextMenu; const commander = config.getCommanderRegister(); const ContextMenu = () => { const handleclick = () => { unmountContextMenu(); }; const forceUpdate = useState(0)[1]; contextMenuState.forceUpdate = () => { forceUpdate((pre) => pre + 1); }; return ( <div style={{ left: contextMenuState.left, top: contextMenuState.top, position: 'fixed', background: 'rgb(24, 23, 23)', }} > <div style={{ width: '100%' }} onClick={() => { commander.exec('redo'); handleclick(); }} > <Button>自定义</Button> </div> </div> ); }; contextMenuState.contextMenu = <ContextMenu></ContextMenu>; style={{ // 自定义右键const contextMenuState = config.getContextMenuState(); const unmountContextMenu = contextMenuState.unmountContextMenu; const commander = config.getCommanderRegister(); const ContextMenu = () => { const handleclick = () => { unmountContextMenu(); }; const forceUpdate = useState(0)[1]; contextMenuState.forceUpdate = () => { forceUpdate((pre) => pre + 1); }; return ( <div style={{ left: contextMenuState.left, top: contextMenuState.top, position: 'fixed', background: 'rgb(24, 23, 23)', }} > <div style={{ width: '100%' }} onClick={() => { commander.exec('redo'); handleclick(); }} > <Button>自定义</Button> </div> </div> ); }; contextMenuState.contextMenu = <ContextMenu></ContextMenu>; left: contextMenuState.left, // 自定义右键const contextMenuState = config.getContextMenuState(); const unmountContextMenu = contextMenuState.unmountContextMenu; const commander = config.getCommanderRegister(); const ContextMenu = () => { const handleclick = () => { unmountContextMenu(); }; const forceUpdate = useState(0)[1]; contextMenuState.forceUpdate = () => { forceUpdate((pre) => pre + 1); }; return ( <div style={{ left: contextMenuState.left, top: contextMenuState.top, position: 'fixed', background: 'rgb(24, 23, 23)', }} > <div style={{ width: '100%' }} onClick={() => { commander.exec('redo'); handleclick(); }} > <Button>自定义</Button> </div> </div> ); }; contextMenuState.contextMenu = <ContextMenu></ContextMenu>; top: contextMenuState.top, // 自定义右键const contextMenuState = config.getContextMenuState(); const unmountContextMenu = contextMenuState.unmountContextMenu; const commander = config.getCommanderRegister(); const ContextMenu = () => { const handleclick = () => { unmountContextMenu(); }; const forceUpdate = useState(0)[1]; contextMenuState.forceUpdate = () => { forceUpdate((pre) => pre + 1); }; return ( <div style={{ left: contextMenuState.left, top: contextMenuState.top, position: 'fixed', background: 'rgb(24, 23, 23)', }} > <div style={{ width: '100%' }} onClick={() => { commander.exec('redo'); handleclick(); }} > <Button>自定义</Button> </div> </div> ); }; contextMenuState.contextMenu = <ContextMenu></ContextMenu>; position: 'fixed', // 自定义右键const contextMenuState = config.getContextMenuState(); const unmountContextMenu = contextMenuState.unmountContextMenu; const commander = config.getCommanderRegister(); const ContextMenu = () => { const handleclick = () => { unmountContextMenu(); }; const forceUpdate = useState(0)[1]; contextMenuState.forceUpdate = () => { forceUpdate((pre) => pre + 1); }; return ( <div style={{ left: contextMenuState.left, top: contextMenuState.top, position: 'fixed', background: 'rgb(24, 23, 23)', }} > <div style={{ width: '100%' }} onClick={() => { commander.exec('redo'); handleclick(); }} > <Button>自定义</Button> </div> </div> ); }; contextMenuState.contextMenu = <ContextMenu></ContextMenu>; background: 'rgb(24, 23, 23)', // 自定义右键const contextMenuState = config.getContextMenuState(); const unmountContextMenu = contextMenuState.unmountContextMenu; const commander = config.getCommanderRegister(); const ContextMenu = () => { const handleclick = () => { unmountContextMenu(); }; const forceUpdate = useState(0)[1]; contextMenuState.forceUpdate = () => { forceUpdate((pre) => pre + 1); }; return ( <div style={{ left: contextMenuState.left, top: contextMenuState.top, position: 'fixed', background: 'rgb(24, 23, 23)', }} > <div style={{ width: '100%' }} onClick={() => { commander.exec('redo'); handleclick(); }} > <Button>自定义</Button> </div> </div> ); }; contextMenuState.contextMenu = <ContextMenu></ContextMenu>; }} // 自定义右键const contextMenuState = config.getContextMenuState(); const unmountContextMenu = contextMenuState.unmountContextMenu; const commander = config.getCommanderRegister(); const ContextMenu = () => { const handleclick = () => { unmountContextMenu(); }; const forceUpdate = useState(0)[1]; contextMenuState.forceUpdate = () => { forceUpdate((pre) => pre + 1); }; return ( <div style={{ left: contextMenuState.left, top: contextMenuState.top, position: 'fixed', background: 'rgb(24, 23, 23)', }} > <div style={{ width: '100%' }} onClick={() => { commander.exec('redo'); handleclick(); }} > <Button>自定义</Button> </div> </div> ); }; contextMenuState.contextMenu = <ContextMenu></ContextMenu>; > // 自定义右键const contextMenuState = config.getContextMenuState(); const unmountContextMenu = contextMenuState.unmountContextMenu; const commander = config.getCommanderRegister(); const ContextMenu = () => { const handleclick = () => { unmountContextMenu(); }; const forceUpdate = useState(0)[1]; contextMenuState.forceUpdate = () => { forceUpdate((pre) => pre + 1); }; return ( <div style={{ left: contextMenuState.left, top: contextMenuState.top, position: 'fixed', background: 'rgb(24, 23, 23)', }} > <div style={{ width: '100%' }} onClick={() => { commander.exec('redo'); handleclick(); }} > <Button>自定义</Button> </div> </div> ); }; contextMenuState.contextMenu = <ContextMenu></ContextMenu>; <div // 自定义右键const contextMenuState = config.getContextMenuState(); const unmountContextMenu = contextMenuState.unmountContextMenu; const commander = config.getCommanderRegister(); const ContextMenu = () => { const handleclick = () => { unmountContextMenu(); }; const forceUpdate = useState(0)[1]; contextMenuState.forceUpdate = () => { forceUpdate((pre) => pre + 1); }; return ( <div style={{ left: contextMenuState.left, top: contextMenuState.top, position: 'fixed', background: 'rgb(24, 23, 23)', }} > <div style={{ width: '100%' }} onClick={() => { commander.exec('redo'); handleclick(); }} > <Button>自定义</Button> </div> </div> ); }; contextMenuState.contextMenu = <ContextMenu></ContextMenu>; style={{ width: '100%' }} // 自定义右键const contextMenuState = config.getContextMenuState(); const unmountContextMenu = contextMenuState.unmountContextMenu; const commander = config.getCommanderRegister(); const ContextMenu = () => { const handleclick = () => { unmountContextMenu(); }; const forceUpdate = useState(0)[1]; contextMenuState.forceUpdate = () => { forceUpdate((pre) => pre + 1); }; return ( <div style={{ left: contextMenuState.left, top: contextMenuState.top, position: 'fixed', background: 'rgb(24, 23, 23)', }} > <div style={{ width: '100%' }} onClick={() => { commander.exec('redo'); handleclick(); }} > <Button>自定义</Button> </div> </div> ); }; contextMenuState.contextMenu = <ContextMenu></ContextMenu>; onClick={() => { // 自定义右键const contextMenuState = config.getContextMenuState(); const unmountContextMenu = contextMenuState.unmountContextMenu; const commander = config.getCommanderRegister(); const ContextMenu = () => { const handleclick = () => { unmountContextMenu(); }; const forceUpdate = useState(0)[1]; contextMenuState.forceUpdate = () => { forceUpdate((pre) => pre + 1); }; return ( <div style={{ left: contextMenuState.left, top: contextMenuState.top, position: 'fixed', background: 'rgb(24, 23, 23)', }} > <div style={{ width: '100%' }} onClick={() => { commander.exec('redo'); handleclick(); }} > <Button>自定义</Button> </div> </div> ); }; contextMenuState.contextMenu = <ContextMenu></ContextMenu>; commander.exec('redo'); // 自定义右键const contextMenuState = config.getContextMenuState(); const unmountContextMenu = contextMenuState.unmountContextMenu; const commander = config.getCommanderRegister(); const ContextMenu = () => { const handleclick = () => { unmountContextMenu(); }; const forceUpdate = useState(0)[1]; contextMenuState.forceUpdate = () => { forceUpdate((pre) => pre + 1); }; return ( <div style={{ left: contextMenuState.left, top: contextMenuState.top, position: 'fixed', background: 'rgb(24, 23, 23)', }} > <div style={{ width: '100%' }} onClick={() => { commander.exec('redo'); handleclick(); }} > <Button>自定义</Button> </div> </div> ); }; contextMenuState.contextMenu = <ContextMenu></ContextMenu>; handleclick(); // 自定义右键const contextMenuState = config.getContextMenuState(); const unmountContextMenu = contextMenuState.unmountContextMenu; const commander = config.getCommanderRegister(); const ContextMenu = () => { const handleclick = () => { unmountContextMenu(); }; const forceUpdate = useState(0)[1]; contextMenuState.forceUpdate = () => { forceUpdate((pre) => pre + 1); }; return ( <div style={{ left: contextMenuState.left, top: contextMenuState.top, position: 'fixed', background: 'rgb(24, 23, 23)', }} > <div style={{ width: '100%' }} onClick={() => { commander.exec('redo'); handleclick(); }} > <Button>自定义</Button> </div> </div> ); }; contextMenuState.contextMenu = <ContextMenu></ContextMenu>; }} // 自定义右键const contextMenuState = config.getContextMenuState(); const unmountContextMenu = contextMenuState.unmountContextMenu; const commander = config.getCommanderRegister(); const ContextMenu = () => { const handleclick = () => { unmountContextMenu(); }; const forceUpdate = useState(0)[1]; contextMenuState.forceUpdate = () => { forceUpdate((pre) => pre + 1); }; return ( <div style={{ left: contextMenuState.left, top: contextMenuState.top, position: 'fixed', background: 'rgb(24, 23, 23)', }} > <div style={{ width: '100%' }} onClick={() => { commander.exec('redo'); handleclick(); }} > <Button>自定义</Button> </div> </div> ); }; contextMenuState.contextMenu = <ContextMenu></ContextMenu>; > // 自定义右键const contextMenuState = config.getContextMenuState(); const unmountContextMenu = contextMenuState.unmountContextMenu; const commander = config.getCommanderRegister(); const ContextMenu = () => { const handleclick = () => { unmountContextMenu(); }; const forceUpdate = useState(0)[1]; contextMenuState.forceUpdate = () => { forceUpdate((pre) => pre + 1); }; return ( <div style={{ left: contextMenuState.left, top: contextMenuState.top, position: 'fixed', background: 'rgb(24, 23, 23)', }} > <div style={{ width: '100%' }} onClick={() => { commander.exec('redo'); handleclick(); }} > <Button>自定义</Button> </div> </div> ); }; contextMenuState.contextMenu = <ContextMenu></ContextMenu>; <Button>自定義</Button> // 自定义右键const contextMenuState = config.getContextMenuState(); const unmountContextMenu = contextMenuState.unmountContextMenu; const commander = config.getCommanderRegister(); const ContextMenu = () => { const handleclick = () => { unmountContextMenu(); }; const forceUpdate = useState(0)[1]; contextMenuState.forceUpdate = () => { forceUpdate((pre) => pre + 1); }; return ( <div style={{ left: contextMenuState.left, top: contextMenuState.top, position: 'fixed', background: 'rgb(24, 23, 23)', }} > <div style={{ width: '100%' }} onClick={() => { commander.exec('redo'); handleclick(); }} > <Button>自定义</Button> </div> </div> ); }; contextMenuState.contextMenu = <ContextMenu></ContextMenu>; </div> // 自定义右键const contextMenuState = config.getContextMenuState(); const unmountContextMenu = contextMenuState.unmountContextMenu; const commander = config.getCommanderRegister(); const ContextMenu = () => { const handleclick = () => { unmountContextMenu(); }; const forceUpdate = useState(0)[1]; contextMenuState.forceUpdate = () => { forceUpdate((pre) => pre + 1); }; return ( <div style={{ left: contextMenuState.left, top: contextMenuState.top, position: 'fixed', background: 'rgb(24, 23, 23)', }} > <div style={{ width: '100%' }} onClick={() => { commander.exec('redo'); handleclick(); }} > <Button>自定义</Button> </div> </div> ); }; contextMenuState.contextMenu = <ContextMenu></ContextMenu>; </div> // 自定义右键const contextMenuState = config.getContextMenuState(); const unmountContextMenu = contextMenuState.unmountContextMenu; const commander = config.getCommanderRegister(); const ContextMenu = () => { const handleclick = () => { unmountContextMenu(); }; const forceUpdate = useState(0)[1]; contextMenuState.forceUpdate = () => { forceUpdate((pre) => pre + 1); }; return ( <div style={{ left: contextMenuState.left, top: contextMenuState.top, position: 'fixed', background: 'rgb(24, 23, 23)', }} > <div style={{ width: '100%' }} onClick={() => { commander.exec('redo'); handleclick(); }} > <Button>自定义</Button> </div> </div> ); }; contextMenuState.contextMenu = <ContextMenu></ContextMenu>; ); // 自定义右键const contextMenuState = config.getContextMenuState(); const unmountContextMenu = contextMenuState.unmountContextMenu; const commander = config.getCommanderRegister(); const ContextMenu = () => { const handleclick = () => { unmountContextMenu(); }; const forceUpdate = useState(0)[1]; contextMenuState.forceUpdate = () => { forceUpdate((pre) => pre + 1); }; return ( <div style={{ left: contextMenuState.left, top: contextMenuState.top, position: 'fixed', background: 'rgb(24, 23, 23)', }} > <div style={{ width: '100%' }} onClick={() => { commander.exec('redo'); handleclick(); }} > <Button>自定义</Button> </div> </div> ); }; contextMenuState.contextMenu = <ContextMenu></ContextMenu>; }; // 自定义右键const contextMenuState = config.getContextMenuState(); const unmountContextMenu = contextMenuState.unmountContextMenu; const commander = config.getCommanderRegister(); const ContextMenu = () => { const handleclick = () => { unmountContextMenu(); }; const forceUpdate = useState(0)[1]; contextMenuState.forceUpdate = () => { forceUpdate((pre) => pre + 1); }; return ( <div style={{ left: contextMenuState.left, top: contextMenuState.top, position: 'fixed', background: 'rgb(24, 23, 23)', }} > <div style={{ width: '100%' }} onClick={() => { commander.exec('redo'); handleclick(); }} > <Button>自定义</Button> </div> </div> ); }; contextMenuState.contextMenu = <ContextMenu></ContextMenu>;

先拿到所以在點擊後需要調用關閉。同時上面的另外,我們還需要在組件內增加強刷,賦值給

4.7 表單驗證提交思路

blank

表單驗證提交有非常多的做法,因為數據全部是聯通的,或者直接寫個表單組件也可以。在不使用表單組件時,簡單的做法是為每個輸入組件做個驗證函數與提交函數。這樣是否驗證就取決於用戶的選取,而拋出的輸入可以讓用戶選擇放到哪,並由用戶去命名變量。

在點擊提交按鈕時,調用所有組件的驗證函數與提交函數,使其拋給上下文,再通過上下文聚合函數聚合成對象,最後可以通過發送函數發送給對應後端,從而完成整個流程。我們可以在

另一種方式是可以專門寫個提交按鈕,固定了參數,以及部分規則,比如規定在頁面中的所有表單都會被收集提交。

那麼我們可以利用數據源,將所有表單輸出內容自動提交給數據源,最後的提交按鈕按數據源規定格式的

後期規劃

後期我們還會在產品功能方面持續迭代優化,如果大家有好的建議, 也可以隨時和我們交流, 也歡迎在github 上積極提

如果大家對可視化搭建或者低代碼/零代碼感興趣,也可以參考我往期的文章或者在評論區交流你的想法和心得,歡迎一起探索前端真正的技術。

github:
團隊:

What do you think?

Written by marketer

blank

信息流廣告行業似乎就在互相卷啊卷,流量都去哪裡了?

blank

【GDC翻譯】“地平線零之曙光”中基於GPU的程序化實時放置系統