From 09e8dfedbefc6021578b20a995412bf53c555afc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=87=91=E5=BB=BA?= <151812800@qq.com> Date: Sun, 23 Oct 2022 23:27:44 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E7=82=B9=E5=87=BB=E4=BA=8B=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/hooks/useLifeHandler.hook.ts | 237 +++++++++++++++++- src/packages/index.d.ts | 7 + src/utils/router.ts | 3 +- .../ChartEventMonacoEditor/index.vue | 7 +- src/views/chart/hooks/useSync.hook.ts | 4 +- .../components/PreviewRenderList/index.vue | 6 +- 6 files changed, 252 insertions(+), 12 deletions(-) diff --git a/src/hooks/useLifeHandler.hook.ts b/src/hooks/useLifeHandler.hook.ts index af471fd6..f8490c6f 100644 --- a/src/hooks/useLifeHandler.hook.ts +++ b/src/hooks/useLifeHandler.hook.ts @@ -1,31 +1,255 @@ import { CreateComponentType, EventLife } from '@/packages/index.d' import * as echarts from 'echarts' import { BackEndFactory } from '@/backend/ibackend' +import { reactive, toRef , watch, computed} from 'vue'; + +/** + * 事件测试: + * +切换显示名称为 饼图 和 柱状图 的图标 +const range = runtime.fn.selectComponents("饼图 柱状图") +const h = runtime.fn.getChartConfig(range, "hide") +runtime.fn.setChartConfig(range, "hide", !h) + +修改一个名称 柱状图001 组件id 2wolqibrx3c000 的图表数据,以下两句等效 +runtime.fn.setChartConfig("柱状图001", "dataset", {"dimensions":["product","data1","data2"],"source":[{"product":"Mon","data1":120,"data2":130}]}) +runtime.fn.setChartConfig("#2wolqibrx3c000", "dataset", {"dimensions":["product","data1","data2"],"source":[{"product":"Mon","data1":120,"data2":230}]}) + +找到一个组并隐藏 +const c = runtime.fn.selectOneComponent("分组") +if(c){ + console.log(runtime.fn.getChartConfig(c, "isGroup" )) + runtime.fn.setChartConfig(c, "hide", true) +} + +调用组件 exposed 函数的例子 +组件中增加: defineExpose({ actionTest:actionTest }) +以下调用名称为 柱状图 组件的 actionTest +runtime.fn.callExposed("柱状图", "actionTest") + + +数据驱动界面: +图表A 的 MOUNTED 加入对 status1 的 Watch, = "0" 隐藏 +watch(()=>runtime.variables.status1, newValue => runtime.fn.setChartConfig(this, "hide", newValue == "0")) +图表B 的 MOUNTED 也加入对 status1 的 Watch = "1" 隐藏 +watch(()=>runtime.variables.status1, newValue => runtime.fn.setChartConfig(this, "hide", newValue == "1")) +点击事件代码,实现图表A 和 图表B 的切换显示: +if(runtime.variables.status1 == "0"){ + runtime.variables.status1 = "1" +} else{ + runtime.variables.status1 = "0" +} + +图表A 的 MOUNTED 加入对 data1 的 Watch +watch(()=>runtime.datasets.data1, +newValue => runtime.fn.setChartConfig(this, "dataset", newValue)) +图表B 的 MOUNTED 加入对 data1 的 Watch +watch(()=>runtime.datasets.data1, +newValue => runtime.fn.setChartConfig(this, "dataset", newValue)) +点击事件代码,修改datasets.data1,同时更新图表A 和 图表B 的数据 : +runtime.datasets.data1 = {"dimensions":["product","data1","data2"],"source":[{"product":"Mon","data1":120,"data2":230}]} + + * + */ + + + + // * 初始化 export const useSystemInit = async () => { const res = await BackEndFactory.init({}) as any; } +const getOneChartConfig = (component:any, configName:string, params?:any)=>{ + let root = null + if(component.proxy.chartConfig) root = component.proxy.chartConfig + else if (component.proxy.groupData) root = component.proxy.groupData + // if(!root) return null + switch(configName){ + case "hide": + return root.status.hide + break; + case "dataset": + return root.option.dataset + break; + case "isGroup": + return root.isGroup + break; + case "key": + return root.key + break; + case "attr": + return root.attr + break; + case "name": + return root.chartConfig.title + } +} + +const setOneChartConfig = (component:any, configName:string, newValue:any, params?:any)=>{ + let root = null + if(component.proxy.chartConfig) root = component.proxy.chartConfig + else if (component.proxy.groupData) root = component.proxy.groupData + switch(configName){ + case "hide": + root.status.hide = newValue + break; + case "dataset": + root.option.dataset = newValue + break; + } +} + + +/** + * 选择器语法:参考 css selectors + * 名称 组件名称,不能有空格和特殊字符(. # 引号等) + * [name=名称] Todo + * #id 组件编号 + * .key 组件类型 Todo + * @param selectors + * @returns [] + */ +const getComponentsBySelectors = (selectors:string):any[]=>{ + // 返回:数组,可能多个 + let rtn:any[] = [] + const ar = selectors.split(" ") + for(let a of ar){ + rtn = rtn.concat(getComponentsBySelector(a)) + } + return rtn +} + +const getComponentsBySelector = (selector:string):any[]=>{ + // 返回:数组,可能多个 + const rtn:any[] = [] + if(selector.substring(0,1) == "#") + { + const key = selector.substring(1) + if(key in components){ + return [components[key]] + } + return rtn + } + for (let key in components) { + if(getOneChartConfig(components[key], "name") == selector){ + rtn.push(components[key]) + } + } + return rtn +} + + // 所有图表组件集合对象 const components: { [K in string]?: any } = {} +const runtime = { + // 变量,管理各种状态 + variables:reactive({}), + // 数据集 + datasets:reactive({}), + // 组件列表 {} + components:components, + // 帮助类 + fn:{ + /** + * 选择一个组件 + * @param selectors string 选择器语法 | component | [component] + * @return 第一个符合要求的 component 或 null + */ + selectOneComponent:(selectors:any)=>{ + const cList = runtime.fn.selectComponents(selectors) + if(cList.length > 0){ + return cList[0] + } + return null + }, + /** + * 选择组件 + * @param selectors string 选择器语法 | component | [component] + * @return 要求的 [component] 或 [] + */ + selectComponents:(selectors:any):any[]=>{ + if(!selectors) return [] + if(typeof selectors == "string") return getComponentsBySelectors(selectors) + if(Array.isArray(selectors)) return selectors + return [selectors] + }, + /** + * 获取组件的值,如果多个,使用第一个 + * @param selectors string 选择器语法 | component | [component] + * @param configName 配置名称 + * @param params 备用参数,可选 + * @returns 配置的值 + */ + getChartConfig:(selectors:any, configName:string, params?:any)=>{ + const component:any = runtime.fn.selectOneComponent(selectors) + if(!component && !component.proxy) return null + return getOneChartConfig(component, configName, params) + }, + /** + * 设置组件的值,支持多个 + * @param selectors string 选择器语法 | component | [component] + * @param configName 配置名称 + * @param newValue 新值 + * @param params 备用参数,可选 + * @returns 配置的值 + */ + setChartConfig:(selectors:any, configName:string, newValue:any, params?:any)=>{ + const cList:any[] = runtime.fn.selectComponents(selectors) + for(let c of cList){ + if(!c && !c.proxy) return null + setOneChartConfig(c, configName, newValue, params) + } + }, + /** + * 调用组件暴露的函数,组件中使用 defineExpose 进行定义 + * @param selectors string 选择器语法 | component | [component] + * @param action 组件中 defineExpose 的函数名 + * @param params 调用的参数只支持一个参数或没有参数 + * @returns 无 + */ + callExposed:(selectors:any, action:string, params?:any)=>{ + const cList:any[] = runtime.fn.selectComponents(selectors) + for(let c of cList){ + if(!c && !c.exposed) return null + if(typeof c.exposed[action] == "function") c.exposed[action](params) + } + } + } +} + // 项目提供的npm 包变量 -export const npmPkgs = { echarts } +export const npmPkgs = { echarts, toRef , watch, computed, runtime } export const useLifeHandler = (chartConfig: CreateComponentType) => { const events = chartConfig.events || {} // 生成生命周期事件 - const lifeEvents = { + let lifeEvents = { [EventLife.BEFORE_MOUNT](e: any) { // 存储组件 components[chartConfig.id] = e.component const fnStr = (events[EventLife.BEFORE_MOUNT] || '').trim() - generateFunc(fnStr, e) + generateFunc(fnStr, e, e.component) }, [EventLife.MOUNTED](e: any) { const fnStr = (events[EventLife.MOUNTED] || '').trim() - generateFunc(fnStr, e) + generateFunc(fnStr, e, e.component) + } + } + // 遍历,按需侦听 + for(let key in EventLife) + { + if(key != "BEFORE_MOUNT" && key != "MOUNTED"){ + const k = EventLife[key] + const fnStr = (events[k] || '').trim() + if(fnStr){ + lifeEvents[k] = (e:any) => { + const fnStr = (events[k] || '').trim() + generateFunc(fnStr, e, components[chartConfig.id]) + } + } } } return lifeEvents @@ -36,7 +260,8 @@ export const useLifeHandler = (chartConfig: CreateComponentType) => { * @param fnStr 用户方法体代码 * @param e 执行生命周期的动态组件实例 */ -function generateFunc(fnStr: string, e: any) { +function generateFunc(fnStr: string, e: any, component:any) { + if(fnStr == "") return try { // npmPkgs 便于拷贝 echarts 示例时设置option 的formatter等相关内容 Function(` @@ -46,7 +271,7 @@ function generateFunc(fnStr: string, e: any) { const {${Object.keys(npmPkgs).join()}} = node_modules; ${fnStr} } - )`)().bind(e?.component)(e, components, npmPkgs) + )`)().bind(component)(e, components, npmPkgs) } catch (error) { console.error(error) } diff --git a/src/packages/index.d.ts b/src/packages/index.d.ts index 94e90c91..402818b4 100644 --- a/src/packages/index.d.ts +++ b/src/packages/index.d.ts @@ -96,6 +96,13 @@ export enum EventLife { MOUNTED = 'vnodeMounted', // 渲染之前 BEFORE_MOUNT = 'vnodeBeforeMount', + // 鼠标事件 + MOUSE_CLICK = 'click', + MOUSE_OVER = "mouseover", + MOUSE_LEAVE = "mouseleave", + // 图表事件 + ECHART_LEGEND_SELECT_CHANGED = "legendselectchanged", + ECHART_HIGH_LIGHT = "highlight" } // 组件实例类 diff --git a/src/utils/router.ts b/src/utils/router.ts index a3fdd87e..22bd6d95 100644 --- a/src/utils/router.ts +++ b/src/utils/router.ts @@ -146,7 +146,8 @@ export const openGiteeSourceCode = () => { * @returns boolean */ export const isPreview = () => { - return document.location.hash.includes('preview') + return false + //return document.location.hash.includes('preview') } /** diff --git a/src/views/chart/ContentConfigurations/components/ChartEvent/components/ChartEventMonacoEditor/index.vue b/src/views/chart/ContentConfigurations/components/ChartEvent/components/ChartEventMonacoEditor/index.vue index 1865164d..110c679b 100644 --- a/src/views/chart/ContentConfigurations/components/ChartEvent/components/ChartEventMonacoEditor/index.vue +++ b/src/views/chart/ContentConfigurations/components/ChartEvent/components/ChartEventMonacoEditor/index.vue @@ -167,7 +167,12 @@ const { DocumentTextIcon, ChevronDownIcon, PencilIcon } = icon.ionicons5 const EventLifeName = { [EventLife.BEFORE_MOUNT]: '渲染之前', - [EventLife.MOUNTED]: '渲染之后' + [EventLife.MOUNTED]: '渲染之后', + [EventLife.MOUSE_CLICK] : '点击', + [EventLife.MOUSE_OVER] : "进入", + [EventLife.MOUSE_LEAVE] : "离开", + [EventLife.ECHART_LEGEND_SELECT_CHANGED] : "选择图例", + [EventLife.ECHART_HIGH_LIGHT] : "高亮" } const EventLifeTip = { diff --git a/src/views/chart/hooks/useSync.hook.ts b/src/views/chart/hooks/useSync.hook.ts index 4cf02651..6b2d970e 100644 --- a/src/views/chart/hooks/useSync.hook.ts +++ b/src/views/chart/hooks/useSync.hook.ts @@ -176,7 +176,7 @@ export const useSync = () => { updateStoreInfo(res.data) // 更新全局数据 if(res.data.content && res.data.content != "{}"){ - await updateComponent(JSON.parse(res.data.content)) + await updateComponent(JSON.parse(res.data.content), true) return } } @@ -246,7 +246,7 @@ export const useSync = () => { clearInterval(syncTiming) }) } - + return { updateComponent, updateStoreInfo, diff --git a/src/views/preview/components/PreviewRenderList/index.vue b/src/views/preview/components/PreviewRenderList/index.vue index af55e9c1..16bc7e72 100644 --- a/src/views/preview/components/PreviewRenderList/index.vue +++ b/src/views/preview/components/PreviewRenderList/index.vue @@ -1,7 +1,7 @@