无法从 Chrome 扩展生成的 iframe 更改元素
Posted
技术标签:
【中文标题】无法从 Chrome 扩展生成的 iframe 更改元素【英文标题】:Can't change element from iframe generated by Chrome Extension 【发布时间】:2017-02-10 16:29:09 【问题描述】:我正在开发 Chrome 扩展程序。目前,有一个内容脚本会返回点击元素的 XPath。另一个内容脚本将iframe
添加到当前html
页面中。在这个iframe
中有一个textarea
字段,当用户点击它时,它应该显示element
的xpath
。
不幸的是,它不起作用。 xpath
已正确生成(使用console.log(path)
测试,但命令:
$('#xh-bar').contents().find('#product-path').val('some_val');
不改变textarea
。你知道问题出在哪里吗?我尝试更改bar.js
和xpathget.js
的顺序,但没有帮助。
manifest.json
"manifest_version": 2,
"name": "Product",
"description": "This is a plugin collaborating with product.com",
"version": "1.0",
"browser_action":
"default_icon": "spy-icon.png",
"default_popup": "popup.html",
"default_title": "Click here!"
,
"icons":
"64":"spy-icon.png"
,
"background":
"scripts": ["authentication.js"]
,
"content_scripts": [
"matches": ["<all_urls>"],
"js": ["jquery-3.1.1.min.js","xpathget.js","bar.js"]
],
"permissions": [
"activeTab",
"https://ajax.googleapis.com/",
"cookies",
"<all_urls>"
],
"web_accessible_resources": [
"bar.html",
],
"content_security_policy": "script-src 'self' https://ajax.googleapis.com; object-src 'self'"
xpathget.js
document.onclick = function (event)
if (event === undefined) event = window.event; // IE hack
var target = 'target' in event ? event.target : event.srcElement; // another IE hack
var root = document.compatMode === 'CSS1Compat' ? document.documentElement : document.body;
var mxy = [event.clientX + root.scrollLeft, event.clientY + root.scrollTop];
var path = getPathTo(target);
var txy = getPageXY(target);
alert(path);
$('#xh-bar').contents().find('#product-spy-price').val('some_val'); # THIS SHOULD ALTER THE TEXTAREA
function getPathTo(element)
if (element.id !== '')
return 'id("' + element.id + '")';
if (element === document.body)
return element.tagName;
var ix = 0;
var siblings = element.parentNode.childNodes;
for (var i = 0; i < siblings.length; i++)
var sibling = siblings[i];
if (sibling === element)
return getPathTo(element.parentNode) + '/' + element.tagName + '[' + (ix + 1) + ']';
if (sibling.nodeType === 1 && sibling.tagName === element.tagName)
ix++;
function getPageXY(element)
var x = 0, y = 0;
while (element)
x += element.offsetLeft;
y += element.offsetTop;
element = element.offsetParent;
return [x, y];
bar.js
$(document).ready(function ()
$('body').append('<iframe src="chrome-extension://some_id/bar.html" id="xh-bar" class=""></iframe>');
);
而生成的iframe是:
<iframe src="chrome-extension://haifbndknpepdhjlcnmpoemlmomnidpe/bar.html" id="xh-bar" class="">HERE IS THE BAR.HTML</iframe>
这是bar.html
,以防万一:
<!doctype html>
<html>
<head>
<title>Product Client</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.0/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/jquery-ui.min.js"></script>
<script src="bootstrap/bootstrap.min.js"></script>
<script src="bootstrap/html5shiv.js"></script>
<script src="bootstrap/respond.min.js"></script>
<script src="bootstrap/usebootstrap.js"></script>
<script src="popup.js"></script>
<script src="productspy.js"></script>
<script src="xpathget.js"></script>
<script src="jsplugins/jquery.cookie.js"></script>
<script src="authentication.js"></script>
<link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/themes/smoothness/jquery-ui.css">
<link href="theme/bootstrap.css" rel="stylesheet">
<link href="theme/usebootstrap.css" rel="stylesheet">
</head>
<body>
<div class="smaller">
<h1>Product Client - Select the product price</h1>
<hr>
<form class="form-horizontal">
<fieldset>
<!-- Form Name -->
<legend>Form Name</legend>
<!-- Text input-->
<div class="form-group">
<label class="col-md-4 control-label" for="textinput">Product Name</label>
<div class="col-md-4">
<input id="textinput" name="textinput" type="text" placeholder="Nissan Patrol"
class="form-control input-md" required="">
</div>
</div>
<!-- Textarea -->
<div class="form-group">
<label class="col-md-4 control-label" for="price">Price</label>
<div class="col-md-4">
<textarea class="form-control" id="product-spy-price" name="price" readonly>This will show the price</textarea>
</div>
</div>
<!-- Button -->
<div class="form-group">
<label class="col-md-4 control-label" for="submit">Send product</label>
<div class="col-md-4">
<button id="submit" name="submit" class="btn btn-primary">Send</button>
</div>
</div>
</fieldset>
</form>
</div>
</body>
</html>
这是在控制台之后:console.log($('#xh-bar').contents());
未捕获的安全错误:无法读取“contentDocument”属性 来自“HTMLIFrameElement”:阻止了具有原点的框架 “http://***.com”来自访问具有原点的框架 “铬扩展://haifbndknpepdhjlcnmpoemlmomnidpe”。框架 请求访问具有“http”协议,被访问的帧 有一个“chrome-extension”协议。协议必须匹配。
【问题讨论】:
我的猜测可能是'same origin policy'问题。$('#xh-bar').contents()
登录到控制台时返回什么?
@charlietfl 试图记录它并返回 Ucaught SecurityError - 我在问题的底部添加了整个错误。我在 SO 上试过了。
与'同源策略'基本相同。您将需要一种不同于不需要访问 iframe 的方法。或许可以使用postMessage
API。还要查看在 iframe 中设置 document.domain
【参考方案1】:
正如上面已经回答的那样 - 由于某些来源策略,您无法从不同于 iFrame 的 URL 加载的页面访问 iFrame 的 DOM。
但是您可以将消息发送到您的 iFrame 并在那里处理它以设置 textarea 的值。
你可以这样做:
发送消息 xpathget.js
...
// Replace your setter
// $('#xh-bar').contents().find('#product-spy-price').val('some_val'); //# THIS SHOULD ALTER THE TEXTAREA
// with
var win = document.getElementById("xh-bar").contentWindow
win.postMessage(
"command":"click","value":path,
chrome.extension.getURL('')
);
...
在bar.html中包含js文件,它会监听你的消息并设置textarea
值:
...
function listener(event)
if("command" in event.data && event.data.command=='click')
console.log(document.getElementById('product-spy-price').value=event.data.value);
if (window.addEventListener)
addEventListener("message", listener, false)
else
attachEvent("onmessage", listener)
...
就是这样:)
P.S> 最好使用chrome.extension.getURL('bar.html')
获取您的 chrome 页面的路径,而不是对其进行硬编码 - 在这种情况下,您可以毫无问题地更改应用程序 ID,并在支持您的应用程序的同时避免许多麻烦。
【讨论】:
以上是关于无法从 Chrome 扩展生成的 iframe 更改元素的主要内容,如果未能解决你的问题,请参考以下文章
javascript chrome扩展:将字符串元素添加到Iframe