从浏览器操作弹出窗口:打开一个新选项卡并填写输入字段

Gle*_*and 3 javascript google-chrome-extension content-script

我正在尝试构建一个基本的 Chrome 扩展程序,该扩展程序从浏览器操作弹出窗口中,在新选项卡中打开一个网站,并填写登录凭据。我可以使用 Chrome 扩展程序打开新页面,但似乎无法将文本输入到输入字段中。

清单文件

{
  "manifest_version": 2,

  "name": "Vena",
  "description": "This extension will allow users to login to vena accounts",
  "version": "1.0",

  "browser_action": {
   "default_icon": "images/icon.png",
   "default_popup": "popup.html"
  },
  "permissions": [
   "activeTab"
   ]
}
Run Code Online (Sandbox Code Playgroud)

弹出窗口.html

<!doctype html>
<html>
  <head>
    <title>Auto-Login</title>
    <script src="popup.js"></script>
  </head>
  <body>
    <h1>Login</h1>
    <button id="checkPage">Login!</button>
  </body>
</html>
Run Code Online (Sandbox Code Playgroud)

弹出窗口.js

document.addEventListener('DOMContentLoaded', function() {
  var checkPageButton = document.getElementById('checkPage');
  checkPageButton.addEventListener('click', function() {

    var newURL = "https://vena.io/";
    chrome.tabs.create({ url: newURL });

    var loginField = document.getElementsByClassName('js-email form-control input-lg');
    var passwordField = document.getElementsByClassName('js-password form-control input-lg');

    loginField.value = 'gsand';
    passwordField.value = '123';


  }, false);
}, false);
Run Code Online (Sandbox Code Playgroud)

如何在新标签页的输入区填写信息?

Mak*_*yen 5

还有一次,您可能想要使用弹出窗口以外的其他东西(例如,只是一个普通的浏览器操作按钮或面板)来测试您的功能。由于弹出窗口会在很多情况下消失,因此调试弹出窗口以外的东西更容易。调试完基本功能后,您可以将其移至弹出窗口并处理特定于使用弹出窗口的问题。

问题

您需要使用内容脚本与网页交互:
主要问题是您必须使用内容脚本与网页交互,例如操作 DOM,如您所愿。内容脚本必须被注入到网页中。这可以通过manifest.json 中content_scripts条目来完成,也可以使用来自后台上下文中的 JavaScript(后台脚本、事件脚本、弹出窗口、面板、包含来自加载项的页面的选项卡等)来完成。因为你正在做的,就是要走的路。chrome.tabs.executeScript()chrome.tabs.executeScript()

附加问题:

  1. chrome.tabs.create()是异步的。您需要等待回调执行,以便选项卡存在才能注入内容脚本。您不能将脚本注入尚不存在的选项卡中。注意:您可以使用其他更复杂的方法来确定何时注入内容脚本,但chrome.tabs.create()在这种情况下,回调是一个很好的方法。
  2. 创建新选项卡后,您需要注入脚本。这不是“主动标签”,所以您需要添加"https://vena.io/*"到您permissions在你的manifest.json
  3. 当内容脚本运行时,您希望与之交互的元素不会立即在页面上可用。您需要等到它们可用。我只是使用setTimeout循环来轮询,直到元素可用。我选择以 250 毫秒的间隔轮询最多 100 次(25 秒)。在第一次延迟之后,元素每次都在那里。
  4. document.getElementsByClassName()返回一个HTMLCollection,而不是单个元素。
  5. 当您激活不同的选项卡时,弹出窗口会关闭。一旦弹出窗口关闭/销毁,您将无法在弹出窗口的代码中进行任何处理。为了解决这个问题:
    1. 在您的chrome.tabs.create(), 包括active:false以防止新选项卡立即变为活动状态。
    2. 调用chrome.tabs.update()的回调chrome.tabs.executeScript()为主动标签一旦内容脚本已被注射(即当你与所有的处理你打算在弹出的做完成)。

代码

只需要在manifest.jsonpopup.js 中进行更改

清单文件

{
  "manifest_version": 2,

  "name": "Vena",
  "description": "This extension will allow users to login to vena accounts",
  "version": "1.0",

  "browser_action": {
     "default_icon": "icon.png",
     "default_popup": "popup.html"
  },
  "permissions": [
    "activeTab", //This is not needed as you never interact with the active tab
    "https://vena.io/*"
  ]
}
Run Code Online (Sandbox Code Playgroud)

弹出窗口.js

document.addEventListener('DOMContentLoaded', function() {
  var checkPageButton = document.getElementById('checkPage');
  checkPageButton.addEventListener('click', function() {
    var newURL = "https://vena.io/";
    //Must not make the tab active, or the popup will be destroyed preventing any
    //  further processing.
    chrome.tabs.create({ url: newURL,active:false }, function(tab){
        console.log('Attempting to inject script into tab:',tab);
        chrome.tabs.executeScript(tab.id,{code:`
            (function(){
                var count = 100; //Only try 100 times
                function changeLoginWhenExists(){
                    var loginField = document.getElementsByClassName('js-email form-control input-lg')[0];
                    var passwordField = document.getElementsByClassName('js-password form-control input-lg')[0];
                    //loginField and passwordField are each an HTMLCollection
                    if( loginField && passwordField ){
                        loginField.value = 'gsand';
                        passwordField.value = '123';
                    } else {
                        if(count-- > 0 ){
                            //The elements we need don't exist yet, wait a bit to try again.
                            //This could more appropriately be a MutationObserver
                            setTimeout(changeLoginWhenExists,250);
                        }
                    }
                }
                changeLoginWhenExists();
            })();
        `},function(results){
            //Now that we are done with processing, make the tab active. This will
            //  close/destroy the popup.
            chrome.tabs.update(tab.id,{active:true});
        });
    });
  }, false);
}, false);
Run Code Online (Sandbox Code Playgroud)

可能需要使用 document.execCommand('insertText', false, text);

根据页面,您可能需要/想要使用:

document.execCommand('insertText', false, textValue);
Run Code Online (Sandbox Code Playgroud)

如果这样做,您将需要首先选择/聚焦所需的元素。这将而不是设置.value属性。您使用的将取决于您实际在做什么以及您正在更改的页面的组成。对于问题中的具体示例,设置元素的.value属性有效。对于插入文本,使用 `document.execCommand('insertText') 更普遍适用。

可能需要一个 MutationObserver

在上面的代码中,我使用setTimeout()循环来延迟,直到所需的元素存在。虽然这在上述情况下有效,但根据您的用例,使用MutationObserver. 在很大程度上,使用哪个取决于您需要多快地响应添加的所需元素以及您通过查找元素在页面上放置的负载类型。有关监视 DOM 更改的更多信息,请参阅:是否有 JavaScript/jQuery DOM 更改侦听器?

用户界面评论

当前,您有一个带有单个按钮的弹出窗口:“登录”。从用户交互的角度来看,使用普通的浏览器操作按钮可能会更好。如果您打算向弹出窗口添加功能,请继续并保留弹出窗口。如果您不打算添加功能,强制您的用户单击两次(单击:打开弹出窗口,然后单击:登录)并没有多大意义,而他们本可以只单击一次。

使用实际的密码管理器

如果这是您想要的功能,而不仅仅是为了学习而拼凑起来的东西,您应该使用真正的密码管理器。安全存储密码并将其正确插入网站的功能非常重要。您很容易犯错误,从而危及您的安全。我强烈建议您调查各种可用的,并选择一个适合您的需求。基本上,我所见过的所有这些都可以轻松地为您提供此时的功能:打开一个弹出窗口;选择站点;进入网站并填写用户名和密码。密码管理器是一个非常重要的项目。这不是一个可以掉以轻心的项目,或者对于没有安全问题经验的人来说。