likes
comments
collection
share

低代码:如何实现不同组件间的级联通信(基础版)

作者站长头像
站长
· 阅读数 44

前言

低代码平台,难点在于不同组件间的级联通信,比如下图,左边组件如何绑定用户自定义事件?右边组件如何接收数据,并实现视图刷新?

低代码:如何实现不同组件间的级联通信(基础版)

我的思路如下:

  1. 找到合适的Event Emitter,发射数据
  2. 将事件代码挂靠到指定元素上,比如点击全区街道等,发射不同的数据
  3. 图表组件接收数据,实现视图刷新

事件发射器

该事件发射器使用ts,其官网如下所示:

billjs.github.io/event-emitt…

我将源码拷贝到项目的utils目录下,并将事件对象挂靠到window下,供代码编辑器内使用

低代码:如何实现不同组件间的级联通信(基础版)

低代码:如何实现不同组件间的级联通信(基础版)

绑定自定义事件到元素上

配置json数据内的事件对象

左侧组件,数据来源于初始化json配置,或用户上传的json数据,故可在该json数据内配置各个元素的click事件,如下图所示:

低代码:如何实现不同组件间的级联通信(基础版)

注意里面的code,我们会将用户编写的代码赋值到该code

将json数据内的事件对象存储到数组内

循环遍历json配置,将事件对象数据存入到definedEvents数组内

// 寻找到上传数据内的自定义事件
export const useDefinedEvents = (dataset: any) => {
  const definedEvents: any = []
  const isEvent = (data: any) => {
    if (data.event?.name) {
      definedEvents.push(data.event)
    }
  }
  const loopChildren = (data: any) => {
    if (data.children?.length) {
      data.children.forEach((a: any) => {
        isEvent(a)
        loopChildren(a)
      })
    }
  }

  if (Array.isArray(dataset)) {
    dataset.forEach(a => {
      loopChildren(a)
    })
  }
  return definedEvents
}

注意:每个event对象,name是其唯一的索引,不可重复

编辑面板显示自定义事件

将组件内的自定义事件,挂靠到对应的targetData内,代码如下所示:

targetData.value.events.definedEvents = useDefinedEvents(parsedData)

targetData为当前正在编辑的组件,其源码如下所示:

// 获取当前对象数据
export const useTargetData = () => {
  const chartEditStore = useChartEditStore()
  const targetData: Ref<CreateComponentType | CreateComponentGroupType> = computed(() => {
    const list = chartEditStore.getComponentList
    const targetIndex = chartEditStore.fetchTargetIndex()
    return list[targetIndex]
  })
  return { targetData, chartEditStore }
}

我们将当前正在编辑的所有组件存储到chartEditStore内,通过指定的当前索引targetIndex,便能找到正在编辑的组件

新增ChartEventDefinedHandle文件夹,在文件夹下新增index.vue内,遍历targetData内的definedEvents,展示自定义事件函数

低代码:如何实现不同组件间的级联通信(基础版)

注意:对definedEvents变量,需使用computed进行赋值,这样才能监测到targetData内的definedEvents变化(我之前使用reactive并无效果)

界面效果如下图所示:

低代码:如何实现不同组件间的级联通信(基础版)

代码编辑器使用monaco-editor,它是微软开源的基于 VS Code 的代码编辑器,运行在浏览器环境中,GitHub项目链接:monaco-editor-demos

事件绑定

通过v-onnew Function实现动态绑定用户编辑的事件

<template>
...
<div
    :class="['right-item', conActive == index ? 'active' : '']"
    v-for="(item, index) in dirList.children"
    :key="index"
    v-on="togAction(item, index)"
  >
    {{ item.name }}
  </div>
...
</template>
<script lang="ts" setup>
const togAction = (item: any, index: number) => {
  const { event } = item
  const definedEvent: { [key: string]: any } = {}
  if (!event) {
    definedEvent['click'] = new Function('')()
    return { ...definedEvent }
  }
  const codeStr = event.code || item.code
  const generateDefinedFunc = () => {
    try {
      return new Function(`
      return (
        async function(){
          ${codeStr}
        }
      )`)()
    } catch (error) {
      console.error(error)
    }
  }
  definedEvent[event.type] = generateDefinedFunc()
  return { ...definedEvent }
}
</script>

event.code即为用户编辑的代码,通过new Function执行代码字符串。

视图刷新

用户在事件代码内,使用事件发射器,发射图表更新数据

globalEvent.fire('update:LineLinearSingle', {
	"dimensions": ["区", "人数"],
	"source": [{
		"街道": "宝安区",
		"人数": 503440
	}]
})

图表组件接收数据,更新视图

const vEchartsSetOption = (data: any) => {
  const options = cloneDeep(props.chartConfig.option)
  options.dataset = data
  options.source = data.source
  option.value = options
  vChartRef.value?.setOption(options)
}
globalEvent.on('update:LineLinearSingle', (evt: any) => {
  const { data } = evt
  if (data) vEchartsSetOption(data)
})

注意点:用户编辑完代码之后,左侧组件,如何更新元素绑定的code代码呢?我使用watchEffect监听targetData.value.events.definedEvents变化,再次更改数据源dirList内的code若大家有更好的办法,欢迎在评论区留言

watchEffect

代码如下所示:

watchEffect(() => {
  const definedEvents = targetData.value?.events?.definedEvents
  definedEvents.forEach((a: any) => {
      const targetIndex = dirList.value?.children.findIndex(
        (b: any) => b.key === a.params.key
      )
      if (targetIndex > -1) {
        dirList.value.children[targetIndex].event.code = a.code
      }
    })
})

缺陷

当页面上有多个同名组件时,事件发射器便有很大局限了,除非fire内的第一个参数能被用户动态配置,否则无法得知更新哪个组件。

转载自:https://juejin.cn/post/7239604559398584381
评论
请登录