javascript - 无法更改 Chrome 扩展生成的 iframe 中的元素

标签 javascript jquery html iframe google-chrome-extension

我正在开发 Chrome 扩展程序。目前,有一个内容脚本返回单击元素的 XPath。另一个内容脚本将 iframe 添加到当前 html 页面中。在此iframe 中,有一个textarea 字段,当用户单击它时,该字段应显示元素xpath

不幸的是,它不起作用。 xpath 已正确生成(使用 console.log(path) 进行测试,但命令:

$('#xh-bar').contents().find('#product-path').val('some_val');

不改变文本区域。你知道问题出在哪里吗?我尝试更改 bar.jsxpathget.js 的顺序,但没有帮助。

ma​​nifest.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());

Uncaught SecurityError: Failed to read the 'contentDocument' property from 'HTMLIFrameElement': Blocked a frame with origin "http://stackoverflow.com" from accessing a frame with origin "chrome-extension://haifbndknpepdhjlcnmpoemlmomnidpe". The frame requesting access has a protocol of "http", the frame being accessed has a protocol of "chrome-extension". Protocols must match.

最佳答案

正如上面已经回答的那样 - 由于某些来源策略,您无法从与 iFrame 的 URL 不同的页面加载的页面访问 iFrame 的 DOM。

但是您可以向 iFrame 发送消息并在那里处理它以设置文本区域的值。

你可以这样做:

发送消息来自 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,并且在支持您的申请的同时避免很多很多麻烦。

关于javascript - 无法更改 Chrome 扩展生成的 iframe 中的元素,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39819557/

相关文章:

javascript - 使用 NextJS 重定向后如何删除查询参数?

javascript - Knockout.js 中使用 if :clause 的嵌套循环

c# - jQuery 表单提交函数中的 AJAX 调用

javascript - 从表中提取一行

javascript - 选择时更改背景颜色

html - 覆盖 Bootstrap 样式

javascript - 如何在Three.js中添加PointerLockControl?

html - 解释边距和处理图 block

jQuery SlideUp/Down 不断重复?

javascript - JS 中的类型转换是如何进行的?