wordpress island.zip,网站为什么要seo?,设计图库,wdcp wordpress#x1f308;个人主页#xff1a;前端青山 #x1f525;系列专栏#xff1a;Vue篇 #x1f516;人终将被年少不可得之物困其一生 依旧青山,本期给大家带来Vue篇专栏内容:Vue-依赖注入-中央事件总线 目录
中央事件总线使用
依赖注入使用
总结
中央事件总线
依赖注入…
个人主页前端青山 系列专栏Vue篇 人终将被年少不可得之物困其一生 依旧青山,本期给大家带来Vue篇专栏内容:Vue-依赖注入-中央事件总线 目录
中央事件总线使用
依赖注入使用
总结
中央事件总线
依赖注入
结言
大家好依旧青山
最近呢也随着需求的变更调优加载数字孪生地图的缓慢要将原有vue3Ts数据大屏子菜单整合到一个地图环境下注无需加载其余地图场景,同一地图环境下切换不同菜单也就是主页面及子菜单调用一次地图环境即可页面很好集合前嵌套但是不同页面对地图的操作该如何呢
那么我首先做的就是封装一个公共的地图调用方法以组件形式引入所有子菜单实现跨组件通信
以数字孪生地图为例
import { ElLoading } from element-plus
import mapJson from /utils/tjbhJson;
import textArr from /utils/textJson;
import cloudRenderer from 51superapi
import { ref, onMounted, onBeforeUnmount,reactive,watchEffect } from vue
// 引入前缀路径
//封装51地图函数
const app new cloudRenderer(mapDiv);
export default function (){let loadingInstance: any; // 在更宽泛的作用域定
const prefixUrl import.meta.env.VITE_APP_BASE_API || ;
//配置51地图参数
const startRenderConfig reactive({url: http://192.168.1.20:8080, //[必须] 云渲染服务地址; 8889:固定端口order: 123456, //[必须] 渲染口令; 在云渲染客户端上获得resolution: [window.innerWidth 1920? 4096 : window.innerWidth,window.innerHeight 1080? 1209 : window.innerHeight], //[可选] 设置渲染场景像素分辨率nodestyle: width:${window.innerWidth 1920? 4096 : window.innerWidth};height:${window.innerHeight 1080? 1209 : window.innerHeight};position:absolute;top:0px;left:0px;bottom:0px;right:0px;margin:auto;, //[可选] 设置渲染场景容器DOM节点样式, 与设置渲染场景像素分辨率配对使用keyboard: keyboardnofn, //[可选] 初始建盘事件, 开启wasd方向键 [选项: keyboard/keyboardnofn; 详见注册键盘事件]setlogmode: true, //[可选] 开启/关闭SuperAPI调用日志, 默认false
})
// 设置初始分辨率
startRenderConfig.resolution [window.innerWidth 1920 ? 4096 : window.innerWidth,window.innerHeight 1080 ? 1209 : window.innerHeight,
];
//围绕中心旋转
let jsonData {time: 50, //相机旋转一周所需要的时间, (单位:秒)direction: stop //clockwise:顺时针; anticlockwise:逆时针; stop:停止旋转
}
//添加区域轮廓
let jsondata2 {id: range_id,coord_type: 0, //坐标类型(0:经纬度坐标, 1:cad坐标)cad_mapkey: , //CAD基准点Key值, 项目中约定coord_z: 0, //高度(单位:米)coord_z_type: 0, //坐标高度类型(0:相对3D世界表面1:相对3D世界地面2:相对3D世界海拔; 注:cad坐标无效)type: loop_line, //样式类型; 注①color: ffffff, //轮廓颜色(HEXA颜色值)range_height: 60, //围栏高度(单位:米)stroke_weight: 10, //底部轮廓线宽度(单位:米; 注: 区域中含有内环inner_points时无效)fill_area: none, //底部区域填充类型; 注②geojson: mapJson, //geojson数据; 注③
}
//添加3d文字信息与区域轮廓
const pushAllCovering () {app.SuperAPI(Add3DText, textArr, (status: any) {console.log(status); //成功、失败回调});//添加区域轮廓app.SuperAPI(AddGeoRange, jsondata2).then((_back: any) {})
}
//初始地图视角
const Camejsondata {coord_type: 0, //坐标类型(0:经纬度坐标, 1:cad坐标)cad_mapkey: , //CAD基准点Key值, 项目中约定coord_z: 2.06, //海拔高度(单位:米)center_coord: 117.689178,39.01527, //中心点的坐标 lng,latarm_distance: 3000, //镜头距中心点距离(单位:米)pitch: 30, //镜头俯仰角(5~89)yaw: 70, //镜头偏航角(0正北, 0~359)fly: true //true: 飞行动画(有一个短暂飞行动画,并按照arm_distance,pitch,yaw设置镜头);//false: 立刻跳转过去(瞬移)
}
//设置渲染质量
let jsonDate {quality: epic //low:低; medium:中; high:高; epic:超高;
}
// 地图事件注册函数
const myHandleResponseFunction (data: string) {const jsonObject typeof data object ? JSON.parse(JSON.stringify(data)) : JSON.parse(data);switch (jsonObject.func_name) {case APIAlready:app.SuperAPI(RemoveAllCovering, {covering_type: all, //覆盖物类型, 详见下表}).then((_back: any) {console.log(_back);});pushAllCovering(); //添加区域轮廓//设置镜头绕场景中心点旋转app.SuperAPI(SetCameraRotate, jsonData, (e: any) {
})//设置当前场景镜头视界app.SuperAPI(SetCameraInfo, Camejsondata, (status: any) {})app.SuperAPI(SetRenderQuality, jsonDate, (status:any) {console.log(status,设置渲染质量); //成功、失败回调})loadingInstance.close();break;case OnPOIClick:const coord jsonObject.args.coord;const poiId jsonObject.args.id;console.log(poiId,poiId)break;}return data;
}
const myStartRender async () {try {// 设置初始分辨率
startRenderConfig.resolution [window.innerWidth 1920 ? 4096 : window.innerWidth,window.innerHeight 1080 ? 1209 : window.innerHeight,
];await app.startRender(startRenderConfig).then((el: any) {loadingInstance ElLoading.service({ // 赋值给外部变量lock: true,text: 地图加载中,background: rgba(0, 0, 0, 0.7),});// 事件注册事件监听处理器函数, 接收所有从云渲染返回的事件, 数据等信息app.RegisterCloudResponse(myHandleResponseFunction);})} catch (error) {console.error(error:, error)}
}
const SuperAPI () {//先删除全部覆盖物 覆盖物类型, 详见下表app.SuperAPI(RemoveAllCovering, { covering_type: poi }, (status: any) {console.log(status); //成功、失败回调})
}
// 监听窗口大小变化
watchEffect(() {startRenderConfig.resolution [window.innerWidth 1920 ? 4096 : window.innerWidth,window.innerHeight 1080 ? 1209 : window.innerHeight,];
});
return { app, startRenderConfig, myStartRender, myHandleResponseFunction,prefixUrl,loadingInstance, SuperAPI }
}
把公共地图渲染部分封装为一个ts文件并暴露出myStartRender函数方便在主页面onMounted函数中调用并渲染地图依次执行即可那么大家可以看到还暴露出一个app进行全局调用是因为这个数字孪生地图的操作都要以app.(地图操作Api)的形式调用
最终我们在页面中删除公共部分,只需引入公共函数即可!
templatediv idmain-content!-- 地图盒子 --div idmapDiv/divHeader :naturalHazardsheader/div v-ifheader 主页面NaturalHazard//divdiv v-else-ifheader 菜单一EarlyWarningDetection //divdiv v-else-ifheader 菜单二DisasterGeneralData //divdiv v-else-ifheader 菜单三JobFacilities //divdiv v-else-ifheader 菜单四RiskHiddenDanger //divdiv v-else-ifheader 菜单五VideoSurveillance //divdiv v-else-ifheader 菜单六HydrologicMonitoring //divdiv v-else-ifheader 菜单七FloodFightingMaterials //divdiv v-else-ifheader 菜单八RescueTeam //div/div
/template
script langts setup
import { ref, onMounted, onBeforeUnmount, nextTick, provide } from vue;
//引入51地图SuperAPI
import useSuperApi from /utils/useSuperApi
const {app, prefixUrl,SuperAPI,
} useSuperApi()
onMounted(() {nextTick(() {myStartRender()})
});
onBeforeUnmount(() {app.StopRenderCloud(); //关闭云渲染, 释放资源
})
/script
那么随之而来问题也就来了当地图出现poi点的时候我们点击对应的poi点肯定要实现不同的事件我们现在所封装的app暴露出来可以进行打点操作,点击poi点的操作是由地图函数内部执行
// 地图事件注册函数
const myHandleResponseFunction (data: string) {const jsonObject typeof data object ? JSON.parse(JSON.stringify(data)) : JSON.parse(data);switch (jsonObject.func_name) {case OnPOIClick:const coord jsonObject.args.coord;const poiId jsonObject.args.id;console.log(poiId,poiId点击poi点所获得的id及经纬度)break;}return data;
}
在没有整合之前调用的时候是在当前页面的地图函数下执行,请看下方
// 地图事件注册函数
const myHandleResponseFunction (data: string) {const jsonObject typeof data object ? JSON.parse(JSON.stringify(data)) : JSON.parse(data);switch (jsonObject.func_name) {case OnPOIClick:const coord jsonObject.args.coord;const poiId jsonObject.args.id;handlePOIClick(poiId, coord);break;}return data;
}
// 处理自定义POI Label点击事件的函数
const handlePOIClick (poiId: string, coord: string) {const [type, id] poiId.split(_); // 分割前缀和IDswitch (type) { // 假设id格式为type_ID通过前缀区分类型case ggwhcs://公共文化场所handelGgwhcs(id);break;case lyjq://旅游景区handelLyjq(id);break;default:console.log(未识别的POI类型: ${poiId});break;}
}
那么现在我们封装成一个公共函数,且渲染地图只在主页面调用,就要想办法将函数内部的poiId和coord作为参数暴露出去方便我们每个子页面调用执行不同的操作,这里我就想到了vue的中央事件总线和依赖注入!
Vue3提供了多种机制来支持组件间的通信包括中央事件总线和依赖注入。选择哪种方式取决于具体的应用场景和需求
中央事件总线使用
在处理地图的poi点点击事件时,我们可以先使用中央事件总线来执行我们组件不同页面点击poi点的处理逻辑,
首先,在utils文件夹下创建一个EventBus.ts文件
//封装中央事件总线
class EventBus {private events: Recordstring, Function[] {};
on(event: string, callback: Function) {if (!this.events[event]) {this.events[event] [];}this.events[event].push(callback);}
off(event: string, callback: Function) {if (!this.events[event]) return;this.events[event] this.events[event].filter(cb cb ! callback);}
emit(event: string, ...args: any[]) {if (!this.events[event]) return;this.events[event].forEach(callback callback(...args));}
}
const eventBus new EventBus();
export default eventBus;
在main.ts中创建一个全局的事件总线
app.config.globalProperties.$bus {}; // 直接在全局属性中创建事件总线
然后再封装的内部地图函数poi点击事件时进行发送事件
case OnPOIClick:const coord jsonObject.args.coord;const poiId jsonObject.args.id;console.log(poiId,poiId)eventBus.emit(poi-click, poiId, coord); // 发送事件break;
然后再主页面和各个子页面引入eventBus,在onMounted和onBeforeUnmount监听和移出事件总线
onMounted(() {nextTick(() {eventBus.on(poi-click, handlePOIClick);//handlePOIClick为poi点击事件init();//初始化函数})
});
onBeforeUnmount(() {//移出监听eventBus.off(poi-click, handlePOIClick);
})
这时,不管是我们的主页面,还是子菜单,都可以在切换的时候对应页面的poi点进行不同的处理逻辑了
依赖注入使用
单个菜单调用地图不同服务的事情解决了那子菜单和主页面或子菜单和子菜单之间还有通信的复杂操作呢
比如在主页面的Echarts图表中柱状图列出了A页面和B页面的统计数据当我点击不同的柱状图时要切换到当前菜单并直接选中状态及地图出现对应的操作这时基于这种复杂的操作我们可以使用依赖注入
在主页面先通过ref绑定对应组件,并引入provide提供依赖
templatediv idmain-content!-- 地图盒子 --div idmapDiv/divHeader :naturalHazardsheader/div v-ifheader 主页面NaturalHazard//divdiv v-else-ifheader 菜单一EarlyWarningDetection //divdiv v-else-ifheader 菜单二 refdisasterGeneralDataDisasterGeneralData //divdiv v-else-ifheader 菜单三JobFacilities //divdiv v-else-ifheader 菜单四RiskHiddenDanger //divdiv v-else-ifheader 菜单五VideoSurveillance //divdiv v-else-ifheader 菜单六HydrologicMonitoring //divdiv v-else-ifheader 菜单七FloodFightingMaterials //divdiv v-else-ifheader 菜单八RescueTeam //div/div
/template
script setup langts
import { Search } from element-plus/icons-vue
import { ref, onMounted, onBeforeUnmount, nextTick, provide } from vue;
eam/index.vue;
import useSuperApi from /utils/useSuperApi;
import eventBus from /utils/EventBus;
const {app, myStartRender,prefixUrl,SuperAPI
} useSuperApi()
const header refany(自然灾害)
let disasterGeneralData refany()
const setNames (name: any) {//这里我们提供一个函数来接收传进来的name
}
provide(setNames,setNames)
onMounted(() {nextTick(() {myStartRender()})
});
onBeforeUnmount(() {app.StopRenderCloud(); //关闭云渲染, 释放资源
})
/script
style scoped langscss
/style
然后在我们的图表组件页面中注入依赖
let setNames: any inject(setNames)
当我们点击对应的echarts图表时 zgrwczqktance.value.on(click, (params: any) {nextTick(() {setNames(params.name)//传入对应name})});
那么我们子菜单页面肯定是要通过传入的name来执行不同的地图操作或展示详情等逻辑...
const setName (name: any) {const mappings:any {菜单一: [1, 菜单一],菜单二: [3, 菜单二],菜单三: [6, 菜单三],菜单四: [11, 菜单四],菜单五: [7, 菜单五],};const [id, description] mappings[name] || [];if (id ! undefined) {(name 菜单一 || name 菜单二 || name 菜单四 || name 菜单五 || name 菜单三)? abreastClicks(id, description): abreastClick(id, description);}
};
然后我们把这个方法通过defineExpose给暴露出去
defineExpose({setName
})
最后在我们的主页面通过ref所绑定实例再取到依赖注入传入的参数和暴露的内部方法来进行通信啦
let disasterGeneralData refany()//ref绑定实例
const setNames (name: any) {disasterGeneralData.value.setName(name)//子菜单内部的setName方法(已暴露)
}
总结
中央事件总线 优点 简单易用适用于较小规模的应用程序。 不需要修改现有组件即可添加新的监听器。 缺点 随着应用规模的增长事件名称可能会变得难以管理和追踪。 可能导致组件间的耦合度增加。
依赖注入 优点 更好的组织性和可维护性因为依赖关系是显式的。 适用于需要在多个组件间共享数据和服务的情况。 支持树状结构中的组件通信无需直接父子关系。 缺点 对于简单的通信场景可能显得过于复杂。 如果过度使用可能会导致组件之间过于紧密的耦合。
结言 对于简单的跨组件通信可以考虑使用中央事件总线。 对于更复杂的通信需求依赖注入提供了更好的组织性和可维护性。