解決Vue引入百度地圖JSSDK:BMap is undefined 問題

範TE劍發表於2018-01-12

原文連結:解決Vue引入百度地圖JSSDK:BMap is undefined 問題

百度地圖官網文件介紹使用JSSDK時,僅提供了2種引入方式:

  • script引入
  • 非同步載入

但vue專案中僅某一兩個頁面需要用到百度地圖,所以不想在 index.html 中全域性引用。

那在單個vue元件頁面中如何引入呢?

剛開始時,是直接通過 DOM 操作方式插入script標籤到當前document中,如下:

let scriptNode = document.createElement("script");
scriptNode.setAttribute("type", "text/javascript");
scriptNode.setAttribute("src", "http://api.map.baidu.com/api?v=3.0&ak=您的金鑰");
document.body.appendChild(scriptNode);

結果是不行的。

然後考慮使用非同步載入的方式,結合參考網上方案,單獨建立baidu-map.js指令碼:

export default {
  init: function (){
    const AK = "AK金鑰";
    const apiVersion = "3.0";
    const timestamp = new Date().getTime();
    const BMap_URL = "http://api.map.baidu.com/api?v="+ apiVersion +"&ak="+ AK +"&services=&t=" + timestamp;
    return new Promise((resolve, reject) => {
      // 插入script指令碼
      let scriptNode = document.createElement("script");
      scriptNode.setAttribute("type", "text/javascript");
      scriptNode.setAttribute("src", BMap_URL);
      document.body.appendChild(scriptNode);

      // 等待頁面載入完畢回撥
      window.onload = function () {  
         resolve(BMap)  
       } 
    });
  }
}

// -------------------------
// vue引入呼叫
import BaiduMap from `baidu-map`;

...
mounted(){
    BauduMap.init()
    .then((BMap) => {
        console.log(BMap)
        console.log("載入成功...")
    })
}
...  

結果還是不行。

想了下原因,一、可能是vue中window.onload沒有觸發,二、百度地圖JSSDK沒有真正載入成功。

繼續驗證測試,發現window.onload能夠正常觸發,那就是JSSDK沒有載入成功。

直接複製JSSDK URL瀏覽器中開啟 http://api.map.baidu.com/api?v=3.0&ak=您的金鑰關鍵點來了,開啟後內容如下:

(function(){ 
window.BMap_loadScriptTime = (new Date).getTime(); 
document.write(`<script type="text/javascript" src="http://api.map.baidu.com/getscript?v=3.0&ak=您的金鑰&services=&t=20180102163224"></script>`);
})();

從返回內容中看出,立即執行函式中再次插入了另外一個<scirpt>標籤,經檢查發現這個<scirpt>實際並沒有插入成功。

既然如此,那就直接把指令碼放到我們上面的程式碼中去載入,結果就真的成功了。

修改優化後的程式碼如下:

export default {
  init: function (){
    console.log("初始化百度地圖指令碼...");
    const AK = "AK金鑰";
    const apiVersion = "3.0";
    const timestamp = new Date().getTime();
    const BMap_URL = "http://api.map.baidu.com/getscript?v="+ apiVersion +"&ak="+ AK +"&services=&t=" + timestamp;
    return new Promise((resolve, reject) => {
      if(typeof BMap !== "undefined") {
        resolve(BMap);
        return true;
      }

      // 插入script指令碼
      let scriptNode = document.createElement("script");
      scriptNode.setAttribute("type", "text/javascript");
      scriptNode.setAttribute("src", BMap_URL);
      document.body.appendChild(scriptNode);

      // 等待頁面載入完畢回撥
      let timeout = 0;
      let interval = setInterval(() => {
        // 超時10秒載入失敗
        if(timeout >= 20) {
          reject();
          clearInterval(interval);
          console.error("百度地圖指令碼初始化失敗...");
        }
        // 載入成功
        if(typeof BMap !== "undefined") {
          resolve(BMap);
          clearInterval(interval);
          console.log("百度地圖指令碼初始化成功...");
        }
        timeout += 1;
      }, 500);
    });
  }
}  

問題到此就解決了,至於為什麼用官網提供的地址沒有真正載入到JSSDK這個問題有空再研究下。


最新解決方案

export default {
  init: function (){
    //console.log("初始化百度地圖指令碼...");
    const AK = "AK金鑰";
    const BMap_URL = "https://api.map.baidu.com/api?v=2.0&ak="+ AK +"&s=1&callback=onBMapCallback";
    return new Promise((resolve, reject) => {
      // 如果已載入直接返回
      if(typeof BMap !== "undefined") {
        resolve(BMap);
        return true;
      }
      // 百度地圖非同步載入回撥處理
      window.onBMapCallback = function () {
        console.log("百度地圖指令碼初始化成功...");
        resolve(BMap);
      };

      // 插入script指令碼
      let scriptNode = document.createElement("script");
      scriptNode.setAttribute("type", "text/javascript");
      scriptNode.setAttribute("src", BMap_URL);
      document.body.appendChild(scriptNode);
    });
  }
}  

優化如下:

  • 直接使用官網提供的引用地址:http://api.map.baidu.com/api?v=2.0&ak=您的金鑰
  • 啟用 callback 引數,非同步載入必須使用此引數才可以生效
  • 啟用 https 配置,通過 s=1 引數實現
  • API版本為2.0,經測試使用,發現3.0版本在HTTPS環境下是有問題的,指令碼內部某些請求固定使用HTTP,無法正常使用。

相關文章