从零实现一套低代码(保姆级教程)【运行时】 --- 【28】实现模型驱动组件的交互

摘要

即将来到运行时最重要的一部分。在上一章,我们实现了给组件添加事件。但我们会发现,这个事件只是组件单条线路的事件,做不到组件之间的交互

比如,我想点击某个按钮让另外一个按钮的文字发生改变。 所以为了实现这样的效果,我们需要一个全局的模型。那,对于前端来说,就是window上需要有一个变量。我们设为ctx。

我们现在有一个redux管理的comList,用来表示所有组件的全部信息。同时,我们要在window上挂载一个和comList一模一样的一个对象。

同时我们要做到,当comList发生改变的时候更新ctx,ctx发生改变的时候更新视图。

这样的话,我们就可以在事件里面,更改ctx模型的值,从而做出组件之间的交互效果。

1.全局添加ctx

我们要在全局window上添加一个变量ctx,并且能做到redux更新的时候,更新这个ctx。所以来到store下的index.ts文件中,在更新的时候,去给ctx赋值。

const comReducer = (state: any = initialState, action: any) => {
  switch (action.type) {
    case 'changeNowCom': {
      return {...state, dragCom: action.value}
    }
    case 'changeComList': {
      window.ctx = JSON.parse(JSON.stringify(action.value))
      return {...state, comList: action.value}
    }
    case 'changeSelectCom': {
      return {...state, selectCom: action.value}
    }
    default: {
      return state
    }
  }
}

2.修改Button组件实现ctx更改视图

现在我们有了全局对象ctx,为了方便我们快速找到一个节点。我们在window上新增一个查找节点的方法:

const getNodeById = (comId: string): any => {
    const treeList = window.ctx || [];

    for (let i = 0; i < treeList.length; i++) {
        if (treeList[i].comId === comId) {
            return treeList[i]
        } else if (treeList[i].childList) {
            treeList.push(...(treeList[i].childList || []))
        }
    }
}

window.getNodeById = getNodeById;

现在来到我们的Button组件,我们之前Button组件的caption是从props里面拿到的。现在为了我们可以能够修改Button组件的状态,这个值让Button组件自己维护:

  const [ caption, setCaption ] = useState(props.caption)

然后重要的来了,我们把setCaption这个属性给ctx中对应的节点绑定上:

  if(isRender()) {
    const buttonCtx = getNodeById(comId);
    if(buttonCtx) {
      buttonCtx.setCaption = setCaption;
    }
  } 

就这么简单,我们就实现了ctx和组件之间的映射关系。现在我们就可以来尝试一下,来到设计态。我们拖拽两个Button组件。

在这里插入图片描述

给其中一个按钮的onClick事件编写一段这样的代码:

window.getNodeById("comId_1714290466988")
.setCaption("newButton")

就是修改另一个按钮的caption。来到运行时就可以验证结果了。

最后我们整体来修改一下 Button组件:

  const { comStyle, onClick, comId } = props
  const [ caption, setCaption ] = useState(props.caption)
  const [ danger, setDanger ] = useState(props.danger)
  const [ disabled, setDisabled ] = useState(props.disabled)
  const [ ghost, setGhost ] = useState(props.ghost)
  const [ shape, setShape ] = useState(props.shape)
  const [ size, setSize ] = useState(props.size)
  const [ type, setType ] = useState(props.type)

  const IconComponent = require('@ant-design/icons')[type]

  if(isRender()) {
    const buttonCtx = window.getNodeById(comId);
    if(buttonCtx) {
      buttonCtx.setCaption = setCaption;
      buttonCtx.setDanger = setDanger;
      buttonCtx.setDisabled = setDisabled;
      buttonCtx.setGhost = setGhost;
      buttonCtx.setShape = setShape;
      buttonCtx.setSize = setSize;
      buttonCtx.setType = setType;
    }
  } 

我们再来优化一下这段代码,将公共逻辑进行封装。做成一个自定义Hook。


const useStateByProps = (propName: string, props: any, comId: string) => {
  const [state, dispatch] = useState(props[propName])
  // eslint-disable-next-line @typescript-eslint/no-unused-expressions
  if(isRender()) {
    const Ctx = window.getNodeById(comId);
    Ctx['set' + propName.charAt(0).toLocaleUpperCase() + propName.slice(1)] = dispatch;
    return state
  }
}

  const caption = useStateByProps('caption', props, comId)
  const danger = useStateByProps('danger', props, comId)
  const disabled = useStateByProps('disabled', props, comId)
  const ghost = useStateByProps('ghost', props, comId)
  const shape = useStateByProps('shape', props, comId)
  const size = useStateByProps('size', props, comId)
  const type = useStateByProps('type', props, comId)

博主补充

到此,其实运行时比较核心的逻辑就已经完成了。读者可以把其他组件也像这样补充一下。

这部分代码提交在github上
https://github.com/TeacherXin/XinBuilder
commit: fix: 第二十三节:实现模型驱动组件的交互

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-04-29 03:58:01       94 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-04-29 03:58:01       100 阅读
  3. 在Django里面运行非项目文件

    2024-04-29 03:58:01       82 阅读
  4. Python语言-面向对象

    2024-04-29 03:58:01       91 阅读

热门阅读

  1. wpf 按钮禁用样式

    2024-04-29 03:58:01       34 阅读
  2. 模型(model)和扩散模型(diffusion)

    2024-04-29 03:58:01       30 阅读
  3. WPF之Button组件

    2024-04-29 03:58:01       30 阅读
  4. 【高等数学】第十章 -- 差分方程

    2024-04-29 03:58:01       30 阅读
  5. Git 的基本概念和使用方式

    2024-04-29 03:58:01       31 阅读
  6. python 组合判断

    2024-04-29 03:58:01       30 阅读
  7. [HDLBits] Sim/circuit5

    2024-04-29 03:58:01       27 阅读
  8. C++生产者消费者问题实例

    2024-04-29 03:58:01       31 阅读
  9. python 正则表达式

    2024-04-29 03:58:01       26 阅读
  10. 程序会自己抛出错误,干嘛还要写try catch?

    2024-04-29 03:58:01       32 阅读