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

时间:2016-12-12 01:54:39

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

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

的manifest.json

{
  "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"
   ]
}

popup.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>

popup.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);

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

1 个答案:

答案 0 :(得分:2)

另一方面,您可能希望使用弹出窗口之外的其他内容(例如,只是普通的浏览器操作按钮或面板)来测试您的功能。由于弹出窗口会在如此多的条件下消失,因此调试弹出窗口以外的其他内容会更容易。一旦调试了基本功能,就可以将其移动到弹出窗口并处理特定于使用弹出窗口的问题。

问题

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

其他问题:

  1. chrome.tabs.create()是异步的。您需要等待回调执行,以便选项卡存在以便注入内容脚本。您无法将脚本注入到尚不存在的选项卡中。注意:您可以使用其他更复杂的方法来确定何时注入内容脚本,但在这种情况下,chrome.tabs.create()的回调是一种很好的方法。
  2. 创建新标签后,您需要注入一个脚本。这不是&#34;有效标签&#34;,因此您需要将"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.executeScript()的回调中调用chrome.tabs.update()来激活选项卡(即,当您完成弹出窗口中的所有处理时)。 / LI>
  6. 代码

    仅在 manifest.json popup.js 中进行更改。

    的manifest.json

    {
      "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/*"
      ]
    }
    

    popup.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);
    

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

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

    document.execCommand('insertText', false, textValue);
    

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

    可能需要MutationObserver

    在上面的代码中,我使用setTimeout()循环来延迟,直到存在所需的元素。虽然这适用于上述情况,但根据您的使用情况,您可能更适合使用MutationObserver。很大程度上,使用哪个将取决于您需要立即响应所添加的所需元素以及通过查找元素将哪种类型的负载放在页面上。有关观看DOM更改的详细信息,请参阅:Is there a JavaScript/jQuery DOM change listener?

    UI评论

    目前你有一个只有一个按钮的弹出窗口:&#34;登录&#34;。从用户交互的角度来看,最好只使用普通的浏览器操作按钮。如果您打算为弹出窗口添加功能,请继续保持弹出窗口。如果您不打算添加功能,强迫您的用户点击两次(点击:打开弹出窗口,然后点击:登录),只需点击一次就没有多大意义。

    使用实际的密码管理器

    如果这是您想要的功能,而不仅仅是您要学习的东西,您应该使用实际的密码管理器。安全地存储密码并在网站中正确插入密码的功能并非易事。您可以轻松犯错误导致安全性受损。我强烈建议您调查各种可用的,并选择一个符合您需求的。基本上,我所看到的所有内容都可以轻松地为您提供此时的功能:打开弹出窗口;选择网站;转到该站点并填写用户名和密码。密码管理器是一个非常重要的项目。 是一个可以轻易接受的项目,或者是那些没有安全问题经验的人。