动态加载地图JS文件并确保地图正常初始化的解决方案
问题描述
在同一个项目中,不同地市使用不同的地图JS文件。当刷新地图页面时,可能会出现地图加载失败的问题,原因是动态添加的script标签虽然已经插入到DOM中,但对应的JS文件尚未完全加载就尝试初始化地图。需求背景
项目需要支持多个地址的地图功能,但由于不同地市使用的地图JS文件地址不同,因此需要一种灵活的方式来动态加载对应的JS文件。版本1 - 手动切换JS文件
在 `index.html` 中通过注释或取消注释的方式手动切换不同地市的地图JS文件。
- 缺点:每次打包都需要手动修改代码,操作繁琐且容易出错。
版本2 - 动态加载JS文件
通过JavaScript动态创建script标签,并根据系统参数配置判断加载哪个JS文件。
尽管这种方法解决了手动切换的问题,但在页面刷新时仍然可能出现地图加载失败的情况。
版本3 - 最终解决方案
问题分析
即使script标签已成功添加到DOM中,地图仍可能加载失败的原因在于:JS文件加载需要时间,在文件未完全加载前调用地图相关方法会导致错误。
解决思路
通过监听JS文件的加载完成事件(onload),结合页面刷新事件(onbeforeunload)以及本地缓存或Vuex状态管理来确保地图初始化的时机正确。
方案1:本地缓存 + 定时器
在App.vue中动态加载地图JS文件,加载完成后将状态存储到localStorage中。在地图页面中通过定时器检查该状态,一旦状态为true则初始化地图。
<script>
export default {
mounted() {
let mapUrl = '';
if (this.sysConfigData.region === 'ZheX') {
mapUrl = 'http://xx.xx.xx.xx:xxxx/api/gljs?v=1.exp&libraries=visualization';
} else {
mapUrl = 'https://map.qq.com/api/gljs?v=2.exp&key=TencentMapKey';
}
const scriptElement = document.createElement('script');
scriptElement.type = 'text/javascript';
scriptElement.src = mapUrl;
scriptElement.onload = () => {
localStorage.setItem('mapLoaded', 'yes');
};
document.head.appendChild(scriptElement);
}
}
</script>
地图页面代码:
<script>
export default {
mounted() {
window.onbeforeunload = () => {
localStorage.removeItem('mapLoaded');
};
const checkInterval = setInterval(() => {
if (localStorage.getItem('mapLoaded') === 'yes') {
this.initializeMap();
clearInterval(checkInterval);
}
}, 100);
},
methods: {
initializeMap() {
// 地图初始化逻辑
}
}
}
</script>
方案2:Vuex状态管理 + Watch侦听(推荐)
通过Vuex管理地图加载状态,当状态变为true时自动初始化地图。
App.vue代码:
<script>
export default {
mounted() {
let mapUrl = '';
if (this.sysConfigData.region === 'ZheX') {
mapUrl = 'http://xx.xx.xx.xx:xxxx/api/gljs?v=1.exp&libraries=visualization';
} else {
mapUrl = 'https://map.qq.com/api/gljs?v=2.exp&key=TencentMapKey';
}
const scriptElement = document.createElement('script');
scriptElement.type = 'text/javascript';
scriptElement.src = mapUrl;
scriptElement.onload = () => {
this.$store.commit('updateMapStatus', true);
};
document.head.appendChild(scriptElement);
}
}
</script>
地图页面代码:
<script>
import { mapState } from 'vuex';
export default {
computed: {
...mapState(['isMapReady'])
},
watch: {
isMapReady(newVal) {
if (newVal) {
this.initializeMap();
}
}
},
mounted() {
window.onbeforeunload = () => {
this.$store.commit('updateMapStatus', false);
};
},
methods: {
initializeMap() {
// 地图初始化逻辑
}
}
}
</script>
Vuex模块代码:
const state = {
isMapReady: false
};
const mutations = {
updateMapStatus(state, status) {
state.isMapReady = status;
}
};
const actions = {};
const getters = {
isMapReady: state => state.isMapReady
};
export default {
state,
mutations,
actions,
getters
};
总结
关键点在于JS文件加载需要时间,必须等待加载完成后再进行地图初始化。推荐使用Vuex状态管理配合Watch侦听的方式,这种方式更加优雅且易于维护。