1、背景: 项目使用的语言是vue+iview,因为用到了3D,所以找公司买了3d地图的产品,但是问题随之而来。把我们项目需要用到的3d地图封装成一个组件叫3dMap.vue,方便各个页面调用,vue的工作机制是在离开当前页面的时候把当前页面进行销毁,但是由于Cesium的特性,他并没有没销毁,每当访问一次,就会重新new一个Cesium.const Viewer = new Cesium.Viewer(“newID”, { navigation: this.navigation, infoBox: this.infoBox});查看计算机进程会发现,chrome浏览器会同事跑6个以上进程,其中一个是Cesium的,它所占用的内存会随着访问次数的增加不断上涨。2、解决思路: 既然每访问一次3dMap.vue就会new一个Cesium,那能不能就创造一个全局的Cesium,让他一直存在,通过显示与隐藏去控制在每个单页面应用中的显示呢。3、动手:·3.1首先创建一个全局的Cesium,起名global3D.vue,这个只是用来初始化<script> import Cesium from “Cesium”; import aa from ‘../../static/serverconfig.json’ import Vue from ‘vue’; //创建一个div,用来做3d的盒子 const _div = document.createElement(“div”); _div.id = “newID”; _div.style.display = “none”; //挂载在body里面,因为整个系统加载的时候,页面只有body,其他元素都还未加载 document.body.appendChild(div); //用Viewer来接收 const Viewer = new Cesium.Viewer(“newID”, { navigation: this.navigation, infoBox: this.infoBox }) //中间部分写初始化3d需要的方法 //把Viewer抛出去 export default { Viewer, };</script>3.2在main.js中进行挂载import global from ‘./components/global3D’Vue.prototype.GLOBAL = global_3.3 创建一个3DViewer.vue,用来接收全局的Cesium,这个文件中可以写一些设置相机视角,获取经纬度啊等等方法,export default { data() { return { //接收全局的Viewer,这个Viewer是Cesium new 出来的 viewer: this.GLOBAL.Viewer, scene: this.GLOBAL.Viewer.scene }; }, }3.4 单页面应用<template> <div class=“GISbox” id=“GISbox” ref=“gisBox”> <SmViewer ref=“TestSmViewer”></SmViewer> </div> </template><script> import SmViewer from “../../../../components/Common/3D/3DViewer”; export default{ components: {SmViewer}, mounted() { this.setGIS(); }, methods: { setGIS() { //获取到3d的盒子 var gis = document.getElementById(“newID”); //3d在页面中的样式,可根据自己的需求进行调整 gis.style.display = “block”; gis.style.position = “absolute”; gis.style.top = “0px”; gis.style.height = “100%”; gis.style.width = “99%”; //从body中移除 document.body.removeChild(gis); //在本页面中的制定位置进行挂载 document.getElementById(“GISbox”).appendChild(gis); // 加载视角,即写在3DViewer.vue中的方法,父调子 this.$refs.TestSmViewer.setViewAngAngle(); }, destory3D() { //获取到3d的盒子 var gis = document.getElementById(“newID”); //隐藏 gis.style.display = “none”; //从当前页面中移除 document.getElementById(“GISbox”).removeChild(gis); //重新挂载回body document.body.appendChild(gis); } }, beforeDestory(){ //在本页面销毁前进行这一步操作 this.destory3D() } </script>3.4 如果你的3d只是应用在不同的模块中,且这些模块之间没有共同的组件,如下图,在demo1模块中,demo1Page1和demo1Page2共同使用demo1Menu,且只有demo1Page1页面使用3d组件,demo2同,那么到3.3,就可以完美的解决这个问题,但是,如果你的3d是应该在同一个模块,且有共同的组件,那么在不同页面之间跳转的时候就会出现问题。比如,在demo1模块中,demo1Page1和demo1Page2共同使用demo1Menu,且demo1Page1页面和demo1Page2页面都使用了3d组件,demo2同,那么在由demo1里面的页面跳向demo2里面的页面的时候,3d就会丢失了demo1 demo2 demo1Menu demo2Menu demo1Page1 demo2Page1 demo1Page2 demo2Page23.5 解决解决这个问题主要是使用的vue的keep-Alive,首先,在App.vue中,做判断,如果使用了keep-Alive,则走第一个,否则的话,走第二个 <keep-alive> <router-view v-if="$route.meta.keepAlive"></router-view> </keep-alive> <router-view v-if="!$route.meta.keepAlive"></router-view>然后,在router里面,对需要被缓存的模块进行设置 { path: ‘homePage’, component: UMPatrolHomePage, name: ‘UMPatrolHomePage’, meta: { keepAlive: true //需要被缓存 } }最后,在单页面中写入如下,to是要去的那个页面的路径,from是从哪个页面来的那个路径,next()必须执行,否则跳转会被拦截,如果要去的页面或者from的页面使用了3d,则这个页面需要被缓存,即keep.Alive=true,成功缓存后,然后执行销毁操作,这样在不同页面之间切换的时候,就不会出现3d丢失的情况。原理感兴趣的同学可以自行搜索,网上有很多详细解说的文章beforeRouteLeave(to, from, next) { if ( to.name == “UMPatrolHomePage” || to.name == “UMDetailEquipment” || to.name == “虚拟巡检” || to.name == “人员定位详情” || to.name == “管廊安防监控列表” || to.name == “管廊环境监控列表” || from.name == “人员定位详情” || from.name == “虚拟巡检” || from.name == “UMDetailEquipment” || from.name == “UMPatrolHomePage” || from.name == “管廊安防监控列表” || from.name == “管廊环境监控列表” ) { from.meta.keepAlive = true; to.meta.keepAlive = true; this.$destroy(); next(); } else { from.meta.keepAlive = false; to.meta.keepAlive = false; this.$destroy(); next(); }},