簡體   English   中英

如何在使用Browserify時公開Goog​​le地圖的回調功能?

[英]How to expose callback function for Google Maps when using Browserify?

我正在使用Gulp和Browserify捆綁我的JavaScripts。 我需要公開一個應該在Google Maps API加載后執行的回調函數。

如何在不使用window.initMap類的情況下完成這項工作? 這個問題是我需要在initMap中觸發大量其他方法,因此除了使用window.functionName和污染全局命名空間之外,還必須有更好的方法。

另一方面,是否可以排除callback參數並執行類似的操作?

$.getScript('https://maps.googleapis.com/maps/api/js').done(function() {
  initMap();
});

任何幫助將不勝感激。 我花了更多的時間來承認讓它發揮作用。

gulpfile.js:

gulp.task('browserify', ['eslint'], function() {
  return browserify('/src/js/main.js')
    .bundle()
    .pipe(source('main.js'))
    .pipe(buffer())
    .pipe(gulp.dest('/dist/js'))
    .pipe(reload({ stream: true }));
});

main.js:

require('jquery');
require('./map');

map.js:

var map = (function() {
  'use strict';

  var mapElement = $('#map');

  function googleMapsAPI() {
    $.getScript('https://maps.googleapis.com/maps/api/js?callback=initMap');
  }

  function initMap() {
    var theMap = new google.maps.Map(mapElement);
    // functions...
  }

  function init() {
    googleMapsAPI();
  }
});

map.init();

不,不包括callback參數也不行。

谷歌地圖API庫調用要在頁面上加載的一堆其他腳本,然后,當它們全部被加載時,在窗口對象上callback參數。

只需在window對象上聲明它:

var MyApp = {
    init: function() {
         //all your stuff
    }
}

window.initMap = function() {
   window.initMap = null; //set this to null this so that it can't get called anymore....if you want
   MyApp.init();
};

然后只需在頁面上包含腳本標記:

<script src="https://maps.googleapis.com/maps/api/js?callback=initMap"></script>

如果要加載腳本,然后在加載腳本時執行某些操作,則可以在注入script時設置屬性asynconload 通過將所有代碼包裝到IIFE中,我們將保留在IIFE內定義的所有對象的私有 ,從而避免填充全局命名空間window 請參閱以下示例:

// IIFE (Immediately-Invoked Function Expression)
// Keeps all private
!function() {
/**
 * Injects the script asynchronously.
 *
 * @param {String} url: the URL from where the script will be loaded
 * @param {Function} callback: function executed after the script is loaded
 */
function inject(url, callback) {
  var tag = 'script',
    script = document.createElement(tag),
    first = document.getElementsByTagName(tag)[0];
  script.defer = script.async = 1; // true
  script.type = 'text/javascript';
  script.src = url;
  script.onload = callback;
  first.parentNode.insertBefore(script, first);
}

/**
 * Injects and initializes the google maps api script.
 */
function injectMapsApi() {
  var key = 'your-api-key';
  var query = '?key=' + key;
  var url = 'https://maps.googleapis.com/maps/api/js' + query;
  inject(url, initMapsApi);
}

/**
 * Callback that initializes the google maps api script.
 */
function initMapsApi() {
  var maps = window.google.maps;
  // ... code initializations
  console.log(maps);
}

injectMapsApi();

}(); // end IIFE

您需要注冊並聲明API密鑰才能使用Google Maps API。 更多信息:

老實說,我認為這是一個更好的解決方案,只需定義一個全局initMap函數,以便在利用Google Maps異步初始化的同時保持簡單。 這可能聽起來像是黑客攻擊,但您可以為該功能定義一個隨機名稱,然后在Google Maps SDK調用它后將其從全局范圍中刪除。 此機制類似於JSONP中使用的機制。

var functionName = getRandomName();
window[functionName] = function() {
    window[functionName] = undefined;
    // call to your initialization functions
};

這個答案中,您可以看出防止污染全球范圍的方法是使谷歌地圖腳本同步加載,這可能會損害用戶體驗,特別是在智能手機上。

我對谷歌采取的這種方法也存在疑問。 我自己並不喜歡它。

我最近處理這個問題的方法是創建全局函數,其中包括觸發事件來觸發我的實際應用程序javascript。 這樣我的應用程序JS就可以處理地圖API處理了,它是我主要對象之外的一個小型全局函數調用。

function initMap(){
  $(document).ready(function(){
    $(window).on('GoogleMapsLoaded', myObj.init());
    $(window).trigger('GoogleMapsLoaded');
  });
};

我只是在腳本url中包含callback=initMap

更新:另一種選擇是將回調作為函數包含在對象中。 例如:你的對象可能是這樣的

var app = app || {};

(function($){

   $(function(){
      $.extend(app, {
        initMap:function(yourMainWrapDiv){
           //Do whatever you need to do after the map has loaded
        },
        mapLoadFunction(){
           //Map API has loaded, run the init for my whole object
           this.initMap($('#mainWrapper'))
        },
        mainInit: function(){
           ///do all your JS that can or needs  
           // to be done before the map API loads
           this.maybeSetSomeBindings();
        },
        maybeSetSomeBindings: function(){
             //do things
        }
      });
      //On document ready trigger your mainInit
      //To do other things while maps API loads
      app.mainInit()
   });
})(jQuery);

然后,您可以使用回調跳轉到一個全局對象中,並運行您只需要為地圖處理運行的內容。 您的API網址可以使用callback=app.initMap

這也可以保持清潔

更新2:另一個選項(我經過最低限度測試)將使用Google API網址中的callback參數,並將其與您需要的任何其他圖書館鏈接相關聯。 (地方,搜索等)。 https://maps.googleapis.com/maps/api/js?key=YOUR-KEY-HERE&libraries=places例如。

然后在你的對象init函數中設置一個計時器,看看google對象是否可用! 也許是這樣的:

 var app = app || {}; (function($){ $(function(){ $.extend(app, { init:function(){ var self = this; var timer = setInterval(function(){ if ($('.ex').length){ //but really check for google object console.log('things exist google, elements, etc..'); self.next(); clearInterval(timer); } }); }, next:function(){ console.log('google object exists') } }); app.init() }); })(jQuery); 
 <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <div class='ex'>as an example for something to trigger a flag (true/false) to clear the interval</div> 

在任何情況下,你試圖訪問全局對象,在這種情況下app ,作為URL中的回調你將設置callback=app.yourFunctionToCall NOT callback=app.funtionToCall()script標簽也應該有asyncdefer屬性歸因於它促進進一步的html解析(你的應用程序的js應該直接在地圖腳本之后)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM