【问题标题】:Set element value in iFrame - Chrome Extension在 iFrame 中设置元素值 - Chrome 扩展
【发布时间】:2016-03-09 06:14:52
【问题描述】:

我正在尝试将活动选项卡 URL 设置为我在 chrome.browserAction.onClicked 上注入的 Iframe 中的表单字段。

问题是由于安全策略(主页和 iframe 的来源不同),我无法从 content script 访问 iframe。 主网页是外部页面。例如。 wikipedia.com

这是我迄今为止尝试过的。

content_script.js

function onExtensionMessage(request) {
  if (request['iconClicked'] != undefined) {
    var extensionOrigin = 'chrome-extension://' + chrome.runtime.id;
    if (!location.ancestorOrigins.contains(extensionOrigin)) {
        var urlvalue = location.href;
        var iframe = document.createElement('iframe');
        iframe.setAttribute("id", "iFrameS");
        iframe.src = chrome.runtime.getURL('popup.html');
        iframe.addEventListener('load', function (e) {
            // Either set the value of input element in Iframe 
            // here or pass an event to background.js and set it from there
            chrome.extension.sendRequest({'frameloaded': true});
        }, false);                       
        document.body.appendChild(iframe);
    }
    return;
  }
}

function initContentScript() {      
  chrome.extension.onRequest.addListener(onExtensionMessage);
}

initContentScript();

popup.html

<form method="post">
    <input id="url" type="text">
</form>

单击扩展图标后,我向内容脚本传递一条消息以注入 iframe,一旦加载,我想设置字段值。

我已参考此链接Access iframe from content script,但找不到解决方案。

任何帮助将不胜感激。

【问题讨论】:

  • all_frames 已在清单文件中设置为 true。如何从内容脚本中设置 id=url 的输入字段的值?
  • @gaemaf:我知道如何在内容脚本和背景页面之间传递消息。如何在 iframe 中设置字段的值?
  • @gaemaf:如果我使用弹出窗口,解决方案很简单,但如果我点击弹出窗口外的任何位置,弹出窗口就会关闭。除了在弹出窗口上执行检查元素之外,没有办法强制弹出窗口保持打开状态。我唯一的选择是使用 iframe。
  • 如果我很好理解,你想在 iframe 中注入一个页面,然后在这个 iframe 中设置一些值。您已成功注入 iframe,在其中成功加载页面,现在您正在尝试在其中设置值?
  • @EmrysMyrooin:是的,你是对的!

标签: javascript iframe google-chrome-extension


【解决方案1】:

如果您需要将简单数据传递给新创建的 iFrame,您可以在 iFrame 的 src 中使用查询字符串。
创建 iFrame 时:

var winLoc = window.location.href; //I think this is what you want to send to your iFrame and populate field value

iframe.src = chrome.runtime.getURL('popup.html?'+winLoc );

在您的 iFrame 脚本拆分网址中:

var activeUrl = location.href.split('?')[1];  
//activeUrl now contains passed data

通过这种方式,您可以连接任意数量的“简单”数据

【讨论】:

  • 如果您想在 iframe 中设置您无权访问/未创建的值怎么办>?
【解决方案2】:

因为您想在 Chrome 网页中动态创建的 iframe 中设置一个值,并且您只需要使用 javascript 来执行此操作,您需要参考 postMessage 将您的数据从主页发送到 iframe。

想象你的主页像:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title></title>
    <style>
        iframe {
            background: #FFF;
            border: 3px solid #000;
            width: 100%;
            height: 50%;
        }
    </style>
    <script>
        window.onload = function() {
            document.getElementById('titleH2').textContent = 'Main page: ' + window.location.href;
            var myIframe = document.getElementById('myIframe').contentWindow;
            document.getElementById('btnSend').addEventListener('click', function(e) {
                e.preventDefault();
                var dataToSendToIframe = {
                    inputValue: document.getElementById('testToSend').value,
                    inputId: 'url'
                }
                // post message to the Iframe running on other domain
                myIframe.postMessage(dataToSendToIframe, 'http://localhost:63342');
            });
        }
    </script>
</head>
<body>
    <h2 id="titleH2">Main page:</h2>
    <p>
        <input id="testToSend" type="text">
    </p>
    <p>
        <button id="btnSend">Send Message</button>
    </p>

    <iframe id="myIframe" src="http://localhost:63342/Projects/StackOverflow/z.html">
  <p>Your browser does not support iframes.</p>
</body>
</html>

在此页面中,您会看到一个指向不同域的 iframe,因此出于安全原因,您无法直接对内部内容进行操作(参考 CORS)。 使用 postMessage 您可以简单地将数据发送到您的 iframe:

myIframe.postMessage(dataToSendToIframe, 'http://localhost:63342');

另一方面,Iframe(因为您可以控制它)必须包含或类似于:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title></title>
    <style>
    </style>
    <script>
        window.onload = function() {
            document.getElementById('titleH1').textContent = 'Iframe on different domain: ' + window.location.href;
            var inputUrl = document.getElementById('url');
            function receiveMessage(e) {
                var origin = e.origin || e.originalEvent.origin;
                // verify the message arrive from the right origin, if not reject
                if (e.origin !== "http://localhost:33232")
                    return;
                document.getElementById(e.data.inputId).value = e.data.inputValue;
            }
            window.addEventListener('message', receiveMessage);
        }
    </script>
</head>
<body>
<h1 id="titleH1">Iframe on different domain</h1>
<form method="post">
    <input id="url" type="text">
</form>
</body>
</html>

在 iframe 中,您可以看到传入消息的侦听器:

function receiveMessage(e) {

在监听器中,您必须使用域/源来控制是否接受传入消息。

在下面的快照中(从主页,我在输入字段中写了一些内容并按下按钮,因此 postmessage 将此数据发送到在设置输入字段的不同域上运行的 iframe):

【讨论】:

    【解决方案3】:

    处理 IFrame 和内容脚本并非易事。没有一个非常正式的好方法。

    原则

    当我必须在特定 IFrame 中执行某些操作而不是最终加载其他 IFrame 时,我在 Injected Content Script 的开头设置了一个条件。

    if(_.contains(window.location.href, "myIframePage.html")) runOnIframe()
    
    function runOnIframe()
    {
        // Do what you want
    }
    

    这样runOnIframe 函数将仅在加载myIframePage.html 的 iframe 上运行


    示例

    让一个页面带有两个 IFrame。第一个加载http://google.com/,第二个加载chrome.runtime.getURL('popup.html')(当然是你的IFrame)。

    页面popup.html 包含&lt;input id="myInput" name="myInput"&gt;

    为了能够从后台脚本修改此输入的值,您必须发送一条消息以更正 iframe。 Chrome API 不允许(直到未来的更新)向页面中的特定 IFrame 发送消息。

    诀窍是在您注入的内容脚本中执行此操作:

    contentScript.js

    if(_contains(window.location.href, "myIframePage.html")) runOnIframe
    
    function runOnIframe()
    {
        chrome.extension.onRequest.addListener(onExtensionMessage);
    }
    
    function onExtensionMessage(request)
    {
        if(request.destination !== "iframe.popup.html") return
    
        document.getElementById("myInput").value = request.value
    }
    

    而在您的背景页面中,您只需发送对象:

    {
        destination : "iframe.popup.html",
        value : "Some value to put in the input"
    }
    

    目的地的内容可以是你想要的,它只是为了识别你发送消息的人。这样,您可以通过更改此字段将消息发送到同一页面中的不同 iframe。

    【讨论】:

    • 所以在我的情况下,我应该在加载 iframe 时调用 runOnIframe() (iframe.addEventListener('load', function (e)) 吗?
    • 没有。使用all_frame 标志,contentsScript 也将被注入页面中的所有 iframe。所以你必须把你的专用代码放在内容脚本中。只有当你检测到你在你想要的 iframe 中时才需要调用它
    猜你喜欢
    • 2012-07-08
    • 2017-05-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-02-10
    • 2012-09-22
    • 2012-08-08
    • 1970-01-01
    相关资源
    最近更新 更多