同一项目不同地市地图使用 js 文件不同如何解决_动态添加 script 标签加载js文件(问题:在地图页刷新页面时,地图加载失败。原因:script标签加上了,但是 js 没有加载完成就加载地图)

问题总括

同一项目不同地市地图使用 js 文件不同如何解决_动态添加 script 标签加载js文件(问题:在地图页刷新页面时,地图加载失败。原因:script标签加上了,但是 js 没有加载完成就加载地图)

需求背景

多个地址用同一项目,但是项目中地图使用的 js 地址不同

版本1 - script 标签添加

index.html 中 通过 script 引入各个地市用到地图的 js 文件,需要给哪个地市打包,就打开哪个 script ,其余都注释掉

  • 【缺点】每次打包都需手动打开 js 引入代码,操作繁琐

在这里插入图片描述

版本2 - 动态加载

通过原生 js 操作 dom 动态添加 script 标签:

  • 通过判断系统参数中配置的数据,判断需要加载哪个 js (说明:系统参数中配置的数据 是可在每个地市配置的公共参数)

在这里插入图片描述

版本3(最终解决) - 版本2出现的问题及解决

问题

版本2出现的问题,刷新页面时:

  1. 刷新的当前页面不是地图页面,刷新后跳转到地图页面 - 地图没有问题
  2. 刷新的当前页面是地图页面,刷新后当前页面地图加载失败,且控制台报错
    在这里插入图片描述

原因分析

已经在地图使用前引入 地图的 js 且 script 标签页成功添加,为什么还会报错?

在这里插入图片描述
在这里插入图片描述

【原因】

  • 虽然 js 已经成功引入,但是 js 文件加载时需要时间的(下图可以看出地图 就是加载需要 198毫秒 ),可能 js 文件还没有加载完成,就去调用了地图相关方法,所以会报错
    在这里插入图片描述

【测试一下是不是以上原因】

  • 延迟 1000ms 后再进行地图初始化加载,
    在这里插入图片描述
  • 通过下图可以看出地图加载成功,确实是以上原因造成的地图加载失败,
    在这里插入图片描述

解决

延迟 N毫秒 可行性分析

【延迟 N毫秒 可行性分析】

  • 那我们只需要延迟一下初始化地图的调用就可以,
  • 但是我们直接固定 N毫秒 延迟后后再初始化地图的方法是不可行的,
  • 因为地图 js 加载时间我们是不知道的,
  • 如果 js 加载时间大于我们延迟初始化的时间,
  • 那地图也是会初始化失败的

【结论】不可行

【最终解决】借助 js 加载完成事件 onload + 页面刷新事件 onbeforeunload + ((本地缓存 localStorage + 延时 setInterval) || (store 存数据 + watch 侦听))

【解决思路】

  • App.vue 页面:地图 js 加载完成,本地缓存 TXMapISLoad 作为 js 加载完成标识 → 地图页面通过判断取本地缓存 TXMapISLoad 的值是否为 ‘true’ 来判断地图 js 是否加载完成,以便判断是否初始化地图
  • 地图 页面:
    1. 页面刷新 - 移除 本地 TXMapISLoad 数据缓存
    2. 100毫秒 取一次本地 TXMapISLoad 数据,值为 'true'初始化地图清除定时器
      在这里插入图片描述
  • 本地缓存可换成 store 存数据、EventBus等其他方式

附:解决代码

1. 本地缓存+延时器解决

App.vue

<script>
export default {
  // ... 
  mounted() {
    /** ** 动态添加地图地址 start ****/
    console.log('"添加地图"----', '添加地图开始')
    let url = ''
    if (this.sysConfigData.defFzjg === '浙X') {
      url = 'http://xx.xx.xx.xx:xxxx/api/gljs?v=1.exp&libraries=visualization'
    } else {
      url = 'https://map.qq.com/api/gljs?v=2.exp&key=腾讯地图取key'
    }
    var script = document.createElement('script')
    script.type = 'text/javascript'
    script.src = url
    script.onload = () => {
      /**
       * 地图 js 加载完成,本地缓存 TXMapISLoad 作为 js 加载完成标识:
       *    地图页面通过判断取本地缓存 TXMapISLoad 的值是否为 'true' 来判断地图 js 是否加载完成,以便判断是否初始化地图
       */
      localStorage.setItem('TXMapISLoad', 'true')
    }
    document.head.appendChild(script)
    console.log('"添加地图"----', '添加地图完成')
    /** ** 动态添加地图地址 end ****/
  },
}
</script>

地图页面 @/components/TXMap/index.vue

<script>
export default {
  // ... 
  mounted() {
    // this.initMap()

    /** ** 页面刷新 - 移除本地 TXMapISLoad 数据缓存 ****/
    window.onbeforeunload = () => {
      localStorage.removeItem('TXMapISLoad')
    }

    /**
     * 页面销毁 - 移除本地 TXMapISLoad 数据缓存
     *    此处不考虑页面销毁,
     *    因为如果当前页面销毁时清除 TXMapISLoad 本地数据,
     *    那要是跳转到别的地图页面,地图也加载不出来了,
     *    所以此处不考虑销毁
     */
    // this.$once('hook:beforeDestroy', () => {
    //   localStorage.removeItem('TXMapISLoad')
    // })

    /**
     * 每 100毫秒 取一次本地 TXMapISLoad 数据,
     *    值为 'true' 时 初始化地图 并 清除定时器
     */
    const timer = setInterval(() => {
      const TXMapISLoad = localStorage.getItem('TXMapISLoad')
      if (TXMapISLoad === 'true') {
        this.initMap()
        clearInterval(timer)
      }
    }, 100)
  },
}
</script>

2. store存数据 + watch 侦听解决(最优解)

App.vue

<script>
export default {
  // ... 
  mounted() {
    /** ** 动态添加地图地址 start ****/
    console.log('"添加地图"----', '添加地图开始')
    let url = ''
    if (this.sysConfigData.defFzjg === '浙X') {
      url = 'http://xx.xx.xx.xx:xxxx/api/gljs?v=1.exp&libraries=visualization'
    } else {
      url = 'https://map.qq.com/api/gljs?v=2.exp&key=腾讯地图取key'
    }
    var script = document.createElement('script')
    script.type = 'text/javascript'
    script.src = url
    script.onload = () => {
      /**
       * 地图 js 加载完成,store 中存数据 TXMapISLoad 作为 js 加载完成标识:
       *    地图页面通过侦听 store 中 TXMapISLoad 判断其值是否为 'true' 来判断地图 js 是否加载完成,以便判断是否初始化地图
       */
      this.$store.commit('SET_TXMapISLoad', 'true')
    }
    document.head.appendChild(script)
    console.log('"添加地图"----', '添加地图完成')
    /** ** 动态添加地图地址 end ****/
  },
}
</script>

地图页面 @/components/TXMap/index.vue

<script>
import { mapGetters } from 'vuex'

export default {
  // ... 
  computed: {
    ...mapGetters(['TXMapISLoad'])
  },
  watch: {
    TXMapISLoad() {
      /**
       * 侦听 TXMapISLoad 改变
       *    TXMapISLoad 值为 true 时初始化地图
       */
      if (this.TXMapISLoad === 'true') {
        this.initMap()
      }
    }
  },
  mounted() {
    // this.initMap()

    /** ** 页面刷新 - 将store中数据 TXMapISLoad 值置为 false ****/
    window.onbeforeunload = () => {
      this.$store.commit('SET_TXMapISLoad', 'false')
    }
  },
}
</script>

@/store/modulex/app.js

const state = {
  // ...
  TXMapISLoad: '' // 腾讯地图是否加载完成
}

const mutations = {
  // ...
  SET_TXMapISLoad: (state, payload) => {
    state.TXMapISLoad = payload
  }
}

const actions = {
  // ...
}

const getters = {
  // ...
  TXMapISLoad: (state) => state.TXMapISLoad
}

export default {
  state,
  mutations,
  actions,
  getters
}

@/store/index.js

import Vue from 'vue'
import Vuex from 'vuex'
import createPersistedState from 'vuex-persistedstate'

Vue.use(Vuex)

// https://webpack.js.org/guides/dependency-management/#requirecontext
const modulesFiles = require.context('./modules', true, /\.js$/)

// you do not need `import app from './modules/app'`
// it will auto require all vuex module from modules file
const modules = modulesFiles.keys().reduce((modules, modulePath) => {
  // set './app.js' => 'app'
  const moduleName = modulePath.replace(/^\.\/(.*)\.\w+$/, '$1')
  const value = modulesFiles(modulePath)
  modules[moduleName] = value.default
  return modules
}, {})
const store = new Vuex.Store({
  modules,
  plugins: [createPersistedState()]
})

export default store

【总结 - 注意】

  • 关键点 - js加载是有时间的,要在 js 加载完成后再去初始化地图

  • 7
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
非常感谢提供安徽省的地图。你可以使用地图作为背景,并在上面添加交互元素。以下是一个示例代码,可将提供的地图作为 SVG 背景,并实现点击地市弹出弹窗的功能: ```html <!DOCTYPE html> <html> <head> <style> /* 半透明悬浮框样式 */ #popup { display: none; position: fixed; width: 300px; height: 200px; top: 50%; left: 50%; transform: translate(-50%, -50%); background-color: rgba(0, 0, 0, 0.5); z-index: 9999; color: #fff; padding: 20px; } </style> </head> <body> <div style="position: relative;"> <img src="http://www.mcdkf.com/anhui_map.jpg" alt="安徽省地图" width="600" height="400"> <!-- 安徽省地市地图 --> <svg id="anhui" width="600" height="400" style="position: absolute; top: 0; left: 0;"> <path d="M 100 200 L 200 100 L 300 200 L 200 300 Z" fill="#ccc"></path> <!-- 其他地市地图 --> <!-- ... --> </svg> </div> <!-- 弹窗 --> <div id="popup"> <h2>地市名称</h2> <table> <tr> <th>列1</th> <th>列2</th> <th>列3</th> </tr> <tr> <td></td> <td></td> <td></td> </tr> <!-- 可以添加更多行 --> </table> </div> <script> // 获取地市元素 const anhui = document.getElementById('anhui'); // 获取弹窗元素 const popup = document.getElementById('popup'); // 点击地市弹出弹窗 anhui.addEventListener('click', function() { popup.style.display = 'block'; }); // 点击面其他地方自动关闭弹窗 window.addEventListener('click', function(event) { if (event.target != popup && event.target != anhui) { popup.style.display = 'none'; } }); </script> </body> </html> ``` 请将提供的地图图片保存到本地,并将图片路径替换为 `<img>` 标签的 `src` 属性中的对应路径。然后,你可以根据需要修改地图的样式和具体内容。当点击地市,弹窗会显示,并且点击面其他地方会自动关闭弹窗。弹窗中的列表是一个简单的示例,你可以根据需要进行修改和扩展。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值