如何从Chrome扩展程序获取输入字段值

时间:2018-01-30 16:08:24

标签: javascript google-chrome google-chrome-extension

我正在努力学习如何构建Google Chrome扩展程序。我在网页上有一个联系表单,我用它进行测试。我试图创建一个扩展来读取该表单中的输入字段值。这时,我有:

的manifest.json

{
    "manifest_version": 2,

    "name": "Contact Form Friend",
    "description": "This extension gets contact form info.",
    "version": "1.0",

    "browser_action": {
      "default_icon": "icon.png",
      "default_popup": "popup.html"
    },

    "permissions": [
      "activeTab",
      "<all_urls>"
    ]
  }

popup.html

<!doctype html>
<html>
  <head>
    <title>Getting Started Extension's Popup</title>
    <style type="text/css">
      body {
        margin: 10px;
        white-space: nowrap;
      }

      h1 {
        font-size: 15px;
      }

      #container {
        align-items: center;
        display: flex;
        justify-content: space-between;
      }
    </style>

    <script src="popup.js"></script>
  </head>

    <body>
        <h1>Info</h1>
        <div id="info">

        </div>
    </body>
</html>

popup.js

function getHost() {
    return document.documentElement;
}

document.addEventListener('DOMContentLoaded', () => {
    const infoDisplay = document.getElementById('info');    
    const scriptToRun = `(${getHost})()`;

    // Run the script in the context of the tab
    chrome.tabs.executeScript({
      code: scriptToRun 
    }, (result) => {            
      var values = [];

      var inputFields = result.getElementsByTagName('input');
      infoDisplay.innerHTML = 'inputs: ' + inputFields.length;
      for (var i = 0; i < inputFields.length; i++) {
        values.push(inputFields[i].value);
      }

      infoDisplay.innerHTML += '<br />fields: ' + values.length;
    });
});

当我运行它时,它就像从用户所在的网页(不是扩展程序的网页)访问输入字段一样。我究竟做错了什么?我错过了许可吗?我不相信。但是,它不起作用,我不知道为什么。

感谢您的帮助。

4 个答案:

答案 0 :(得分:4)

根据Gabriel Bleu的报告,您需要一个内容脚本来与Chrome标签页内的网页进行互动。

以下是Chrome扩展程序示例,其中内容脚本向popup.js公开两个“命令”。

请参阅代码注释以获取解释。

manifest.json (与您的相似)

{
  "name": "My ext",
  "version": "0.1",
  "description": "my desc",
  "permissions": [
    "activeTab",
    "<all_urls>"
  ],
  "icons": {
    "128": "icon-128.png"
  },
  "browser_action": {
      "default_title": "My ext",
      "default_icon": "icon.png",
      "default_popup": "popup.html"
  },
  "manifest_version": 2,
  "content_security_policy": "script-src 'self' https://ajax.googleapis.com object-src 'self'"
}

popup.html (类似于你的,除了jQuery用于简单的DOM操作)

<html>
<head>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
    <script type="application/javascript" charset="utf-8" src="popup.js"></script>
</head>
<body class="body-popup">
    <button id="btn_check" class="btn btn-warning">check current tab</button>
    <hr>
    <div id="pg_url"></div>
    <hr>
    <div id="log"></div>
</body>
</html>

<强> popup.js

$(function() {
    $('#btn_check').click(function() { checkCurrentTab(); });
});

function checkCurrentTab() {
    chrome.tabs.query({'active': true, 'lastFocusedWindow': true}, function (tabs) {
        var url = tabs[0].url;
        console.log("checkCurrentTab: "+url);
        $(".pg_url").text(url);

        // request content_script to retrieve title element innerHTML from current tab
        chrome.tabs.sendMessage(tabs[0].id, "getHeadTitle", null, function(obj) {
            console.log("getHeadTitle.from content_script:", obj);
            log("from content_script:"+obj);
        });

    });
}

document.addEventListener('DOMContentLoaded', function () {
    chrome.windows.getCurrent(function (currentWindow) {
        chrome.tabs.query({active: true, windowId: currentWindow.id}, function(activeTabs) {
            // inject content_script to current tab
            chrome.tabs.executeScript(activeTabs[0].id, {file: 'content_script.js', allFrames: false});
        });
    });
});

function log(txt) {
    var h = $("#log").html();
    $("#log").html(h+"<br>"+txt);
}

<强> content_script.js

// you will see this log in console log of current tab in Chrome when the script is injected
console.log("content_script.js");

chrome.runtime.onMessage.addListener(function(cmd, sender, sendResponse) {
    console.log("chrome.runtime.onMessage: "+cmd);
    switch(cmd) {
    case "getHtml":
        // retrieve document HTML and send to popup.js
        sendResponse({title: document.title, url: window.location.href, html: document.documentElement.innerHTML});
        break;
    case "getHeadTitle":
        // retrieve title HTML and send to popup.js
        sendResponse(document.getElementsByTagName("title")[0].innerHTML);
        break;      
    default:
        sendResponse(null);
    }
});

P.S。:显然jQuery不是强制性的

答案 1 :(得分:2)

  

如果您的扩展程序需要与网页进行交互,那么它需要一个内容脚本。内容脚本是一些JavaScript,它在已加载到浏览器中的页面的上下文中执行。将内容脚本视为该加载页面的一部分,而不是作为其打包的扩展(其父扩展)的一部分。

https://developer.chrome.com/extensions/overview#contentScripts

答案 2 :(得分:1)

以下是您收到的错误:

Error in response to tabs.executeScript: TypeError: result.getElementsByTagName is not a function
at Object.chrome.tabs.executeScript [as callback] (chrome-extension://lmaefdnejmkjjmgalgfofdbobhapfmoh/popup.js:15:32)
at HTMLDocument.document.addEventListener (chrome-extension://lmaefdnejmkjjmgalgfofdbobhapfmoh/popup.js:10:17)

我建议使用内容脚本来执行任务,并将结果作为消息发送到弹出窗口,而不是尝试获取popup.js中当前选项卡的DOM。

<强>的manifest.json

{
    "manifest_version": 2,
    "name": "Contact Form Friend",
    "description": "This extension gets contact form info.",
    "version": "1.0",

    "browser_action": {
        "default_icon": "icon.png",
        "default_popup": "popup.html"
    },

    "permissions": [
        "activeTab",
        "<all_urls>"
    ],

    "content_scripts": [
        {
            "matches": ["http://*/*", "https://*/*"],
            "js": ["content.js"]
        }
    ]
}

manifest.json 文件中,您必须添加内容脚本并设置要在其中注入脚本的网站的网址。

<强> popup.js

document.addEventListener('DOMContentLoaded', () => {
    const infoDisplay = document.getElementById('info');    

    window.addEventListener('DOMContentLoaded', function () {
        chrome.tabs.query({active: true, currentWindow: true}, function (tabs) {
            chrome.tabs.sendMessage(tabs[0].id, {}, function (result) {
                infoDisplay.innerHTML = result
            });
        });
    });

});

popup.js 中向内容脚本发送请求,以获取输入字段的数量并将响应插入div

<强> content.js

chrome.runtime.onMessage.addListener(function (msg, sender, response) {
    var values = [];
    var inputFields = document.getElementsByTagName('input');
    var result = 'inputs: ' + inputFields.length;

    for (var i = 0; i < inputFields.length; i++) {
        values.push(inputFields[i].value);
    }

    result += '<br />fields: ' + values.length;

    response(result)
});

创建一个名为content.js的新文件。此文件将被注入网页,并侦听来自popup.js的消息。当消息到达时,它会计算响应并将其发送回popup.js。

要了解有关内容脚本的详情,请查看documentation

答案 3 :(得分:-1)

您的方法的主要问题是您尝试通过message / sendResponse从内容脚本向弹出/后台发送DOM树,以便在那里处理它。您无法通过message / sendResponse发送DOM树。

更好的方法是在内容脚本中处理DOM,并将所需信息(在您的情况下,input值)发送回弹出/背景页面。

一种可行的方法是:

<强> popup.js

document.addEventListener('DOMContentLoaded', () => {
    const infoDisplay = document.getElementById('info');    
    const scriptToRun = `
        var values = [];
        var inputFields = document.getElementsByTagName('input');
        for (var i = 0; i < inputFields.length; i++) {
            values.push(inputFields[i].value);
        }
        values;`;  //all this code will be run on the tab page
                   //and the array "values" will be returned.

    chrome.tabs.executeScript({
      code: scriptToRun 
    }, (result) => {

        infoDisplay.innerHTML = `There are: ${result[0].length} inputs, with these values: <ol><li>${result[0].join("<li>")}`;  
    });
});