如何在使用Browserify时公开Goog​​le地图的回调功能?

时间:2017-08-10 23:23:20

标签: javascript jquery google-maps gulp 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();

4 个答案:

答案 0 :(得分:3)

不,不能包含callback参数。

google maps 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>

答案 1 :(得分:1)

如果要加载脚本,然后在加载脚本时执行某些操作,则可以在注入async时设置属性onloadscript。通过将所有代码包装到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地图API。更多信息:

答案 2 :(得分:0)

老实说,我认为这是一个更好的解决方案,只需定义一个全局initMap函数,以便在利用Google Maps异步初始化的同时保持简单。这可能听起来像是黑客攻击,但您可以为该功能定义一个随机名称,然后在Google Maps SDK调用它后将其从全局范围中删除。此机制类似于JSONP中使用的机制。

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

this answer中,您可以查看防止污染全球范围的方法是使Google地图脚本同步加载,这可能会损害用户体验,特别是在智能手机上。

答案 3 :(得分:0)

Google也采用了这种方法。我自己并不喜欢它。

我最近处理这个问题的方法是创建全局函数,其中包括触发事件来触发我的实际应用程序javascript。这样我的应用程序JS就可以处理地图API处理了,它是我主要对象之外的一个小型全局函数调用。

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

我只需在脚本网址中加入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: 另一个选项(我经过最低限度测试)将是 NOT 使用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),作为您要设置的网址中的回调callback=app.yourFunctionToCall {{1} } callback=app.funtionToCall()标记也应该包含scriptasync属性,以促进进一步的html解析(你的应用程序的js应该直接在地图脚本之后)