使用 Browserify 时如何公开 Google 地图的回调函数?
How to expose callback function for Google Maps when using Browserify?
我正在使用 Gulp 和 Browserify 来捆绑我的 JavaScript。我需要公开一个应在 Google 地图 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();
老实说,我认为这是一个更好的解决方案,简单地定义一个全局 initMap
函数来保持简单,同时利用 Google 地图异步初始化。这听起来像是 hack,但您可以为该函数定义一个随机名称,然后在 Google Maps SDK 调用它后将其从全局范围中删除。这种机制类似于 JSONP 中使用的机制。
var functionName = getRandomName();
window[functionName] = function() {
window[functionName] = undefined;
// call to your initialization functions
};
在中您可以查看防止污染全局范围的方法是使google地图脚本同步加载,这可能会损害用户体验,特别是在智能手机上。
不,不包含callback
参数是不行的。
google maps API 库调用一堆其他脚本加载到页面上,然后,当它们全部加载后,调用 callback
参数window 对象。
只需在 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 密钥才能使用 google 地图 API。更多信息在这里:
我对这种方法有疑问 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 url 可能与 callback=app.initMap
这也可以使它更干净
更新 2:
另一种选择(我进行了最低限度的测试)是 NOT 在 Google API url 中使用 callback
参数,并且 link 它与你需要的任何其他东西,图书馆明智的。 (地点、搜索等)。
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
NOT callback=app.funtionToCall()
你的 script
标签还应该有 async
和 defer
属性,以促进进一步的 html 解析(你的应用程序的 js 应该直接在地图脚本之后)
我正在使用 Gulp 和 Browserify 来捆绑我的 JavaScript。我需要公开一个应在 Google 地图 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();
老实说,我认为这是一个更好的解决方案,简单地定义一个全局 initMap
函数来保持简单,同时利用 Google 地图异步初始化。这听起来像是 hack,但您可以为该函数定义一个随机名称,然后在 Google Maps SDK 调用它后将其从全局范围中删除。这种机制类似于 JSONP 中使用的机制。
var functionName = getRandomName();
window[functionName] = function() {
window[functionName] = undefined;
// call to your initialization functions
};
在
不,不包含callback
参数是不行的。
google maps API 库调用一堆其他脚本加载到页面上,然后,当它们全部加载后,调用 callback
参数window 对象。
只需在 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 密钥才能使用 google 地图 API。更多信息在这里:
我对这种方法有疑问 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 url 可能与 callback=app.initMap
这也可以使它更干净
更新 2:
另一种选择(我进行了最低限度的测试)是 NOT 在 Google API url 中使用 callback
参数,并且 link 它与你需要的任何其他东西,图书馆明智的。 (地点、搜索等)。
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
NOT callback=app.funtionToCall()
你的 script
标签还应该有 async
和 defer
属性,以促进进一步的 html 解析(你的应用程序的 js 应该直接在地图脚本之后)