Javascript Can';t将API连接到Chrome扩展
我正在开发chrome扩展。我想在点击Javascript Can';t将API连接到Chrome扩展,javascript,jquery,google-chrome,google-chrome-extension,Javascript,Jquery,Google Chrome,Google Chrome Extension,我正在开发chrome扩展。我想在点击popup.html中的按钮后,将一些API连接到当前选项卡。我在popup.js中使用此代码: $('button').click(function() { chrome.tabs.executeScript({ file: 'js/ymaps.js' }, function() {}); }); 在ymaps.js中,我使用以下代码将API连接到当前选项卡: var script = document.createEle
popup.html
中的按钮后,将一些API连接到当前选项卡。我在popup.js
中使用此代码:
$('button').click(function() {
chrome.tabs.executeScript({
file: 'js/ymaps.js'
}, function() {});
});
在ymaps.js
中,我使用以下代码将API连接到当前选项卡:
var script = document.createElement('script');
script.src = "http://api-maps.yandex.ru/2.0-stable/?load=package.standard&lang=ru-RU";
document.getElementsByTagName('head')[0].appendChild(script);
使用Yandex映射需要此API。所以,在代码之后,我创建了地图应该放置的位置:
$('body').append('<div id="ymapsbox"></div>');
我想,一切都很清楚,如果你还在阅读,我会解释问题所在。
当我点击我的popup.html
中的按钮时,我进入了Chrome的控制台未捕获的引用错误:未定义ymap
。似乎api库未连接。但是当我手动输入consoleymap
时,我会得到可用方法的列表,所以库已连接。那么,当我从executed.js
-文件调用ymap
-对象时,为什么会出现这样的错误呢
UPD:我还尝试将ymap.ready(init)
包装到$(document.ready()
函数中:
$(document).ready(function() {
ymaps.ready(init);
})
但错误仍在出现。
下面的人说api库可能还没有加载。但这段代码也会产生错误
setTimeout(function() {
ymaps.ready(init);
}, 1500);
我甚至试着这样做
chrome.tabs.onUpdated.addListener(function(tabId, changeInfo) {
if (changeInfo.status == "complete") {
chrome.tabs.executeScript({
file: 'js/gmm/yandexmaps.js'
});
}
});
这不是一个时间问题,而是一个与“执行环境”相关的问题 将脚本注入网页的JS上下文(将脚本标记插入
head
),但尝试从内容脚本的JS上下文调用ymap
。然而,内容脚本“生活”在一个孤立的世界中,无法访问网页的JS上下文(请看)
编辑(感谢Rob的评论)
通常,您可以捆绑库的副本,并将其作为内容脚本注入。在您的特定情况下,这也不会有帮助,因为库本身会将脚本标记插入到中以加载依赖项
可能的解决方案: 根据您的具体要求,您可以:
可能的陷阱:弄乱网页JS,例如覆盖已定义的变量/函数。 此外,如果您需要与chrome.*API交互,此方法将变得越来越复杂(这对于网页的JS上下文不可用,因此您需要设置专有的消息传递机制,例如使用自定义事件)
function initMap() {
ymaps.ready(init);//Waits DOM loaded and run function
var myMap;
function init() {
myMap = new ymaps.Map("ymapsbox", {
center: [55.76, 37.64],
zoom: 7
});
}
}
$('body').append('<div id="ymapsbox"></div>');
var script1 = document.createElement('script');
script1.src = 'http://api-maps.yandex.ru/2.0-stable/?load=package.standard&lang=ru-RU';
script1.addEventListener('load', function() {
var script2 = document.createElement('script');
var script2.textContent = '(' + initMap + ')()';
document.head.appendChild(script2);
});
document.head.appendChild(script1);
函数initMap(){
ready(init);//等待加载DOM并运行函数
var-myMap;
函数init(){
myMap=newymaps.Map(“ymapsbox”{
中间:[55.76,37.64],
缩放:7
});
}
}
$('body')。追加('');
var script1=document.createElement('script');
script1.src=http://api-maps.yandex.ru/2.0-stable/?load=package.standard&lang=ru-汝';
脚本1.addEventListener('load',function(){
var script2=document.createElement('script');
var script2.textContent='('+initMap+')()';
文件.头.子文件(脚本2);
});
文档.头.子文档(脚本1);
Rob已经指出了这个主题的重要资源:ymap
未定义,因为您试图在内容脚本中使用它,而库是在页面上下文中加载的(通过
标记)
通常,您可以通过将库作为内容脚本加载来解决此问题,例如
chrome.tabs.executeScript({
文件:“library.js”
},函数(){
chrome.tabs.executeScript({
文件:“yourscript.js”
});
});
但是,这并不能解决您的问题,因为您的库在
标记中加载了更多的外部脚本。因此,库的一部分仅对网页中的脚本可见(而对内容脚本不可见,因为它们是独立的)
解决方案1:截取
标记并将其作为内容脚本运行。
从中获取scriptTagContext.js
,并在其他内容脚本之前加载它。此模块通过将
(在内容脚本中创建)的执行环境更改为内容脚本来解决您的问题
chrome.tabs.executeScript({
文件:“scriptTagContext.js”
},函数(){
chrome.tabs.executeScript({
文件:“js/ymaps.js”
});
});
有关文档,请参阅。有关解决方案背后的概念的解释,请参见 解决方案2:在页面的上下文中运行 如果您不知何故不想使用前面的解决方案,那么还有另一个选项可以让代码运行。我强烈建议不要使用这种方法,因为它可能(并且会)在其他页面中引起冲突。然而,为了完整性: 在页面上下文中运行所有代码,方法是通过页面中的
标记插入内容脚本(或至少是使用外部库的扩展部分)。这只有在您不使用任何Chrome扩展API的情况下才有效,因为您的脚本将在网页的有限权限下有效运行
例如,您问题中的代码将按如下方式重新构造:
var script=document.createElement('script');
script.src=”http://api-maps.yandex.ru/2.0-stable/?load=packa
function initMap() {
ymaps.ready(init);//Waits DOM loaded and run function
var myMap;
function init() {
myMap = new ymaps.Map("ymapsbox", {
center: [55.76, 37.64],
zoom: 7
});
}
}
$('body').append('<div id="ymapsbox"></div>');
var script1 = document.createElement('script');
script1.src = 'http://api-maps.yandex.ru/2.0-stable/?load=package.standard&lang=ru-RU';
script1.addEventListener('load', function() {
var script2 = document.createElement('script');
var script2.textContent = '(' + initMap + ')()';
document.head.appendChild(script2);
});
document.head.appendChild(script1);