我正在使用Gulp和Browserify来捆绑我的JavaScript。我需要公开一个应在谷歌地图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 }));
});
主.js:
require('jquery');
require('./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
时设置属性async
和onload
。通过将所有代码包装到 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密钥才能使用谷歌地图API。更多信息在这里:
- https://developers.google.com/maps/documentation/javascript/get-api-key
- https://developers.google.com/maps/documentation/javascript/tutorial#Loading_the_Maps_API
老实说,我认为在这里简单地定义一个全局initMap
函数以保持简单,同时利用Google地图异步初始化是一个更好的解决方案。这听起来像是一个黑客,但你可以为函数定义一个随机名称,然后在谷歌地图SDK调用它后将其从全局范围中删除。此机制类似于 JSONP 中使用的机制。
var functionName = getRandomName();
window[functionName] = function() {
window[functionName] = undefined;
// call to your initialization functions
};
在此答案中,您可以查看防止污染全局范围的方法是使Google地图脚本同步加载,这可能会损害用户体验,尤其是在智能手机上。
我对谷歌采取的这种方法也有问题。我自己不太喜欢它。
我最近处理这个问题的方法是创建全局函数,并触发一个事件来触发我的实际应用程序 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 URL中使用callback
参数,并将其与您需要的任何其他库链接。(地点、搜索等(。https://maps.googleapis.com/maps/api/js?key=YOUR-KEY-HERE&libraries=places
例如。
然后在你的对象初始化函数中,只需设置一个计时器,看看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
NOTcallback=app.funtionToCall()
script
标记还应具有归属于它的async
和defer
属性,以促进进一步的 HTML 解析(应用的 JS 应直接在 MAPS 脚本之后(