繁体   English   中英

在浏览器操作弹出窗口中:打开一个新标签并填写输入字段

[英]From a browser action popup: open a new tab and fill input fields

我正在尝试构建一个基本的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);

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

有时,您可能希望使用弹出窗口以外的其他功能(例如,仅浏览器的普通操作按钮或面板)来测试您的功能。 由于弹出窗口在许多情况下都会消失,因此调试弹出窗口以外的内容会更加容易。 调试完基本功能后,可以将其移至弹出窗口并处理使用弹出窗口所特有的问题。

问题

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

其他问题:

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

仅在manifest.jsonpopup.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('insertText')更普遍。

可能需要一个MutationObserver

在上面的代码中,我使用setTimeout()循环延迟直到所需的元素存在。 尽管在上述情况下可行,但根据您的使用情况,使用MutationObserver可能更合适。 在很大程度上,要使用哪种方式取决于您需要立即对添加的所需元素做出响应的程度,以及通过查找元素而对页面施加的负载类型。 有关监视DOM更改的更多信息,请参见: 是否有JavaScript / jQuery DOM更改侦听器?

用户界面评论

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

使用实际的密码管理器

如果这是您想要的功能,而不是只是为了学习而组合在一起的功能,则应使用实际的密码管理器。 安全存储密码并将其正确插入网站的功能并非易事。 您很容易犯错误,从而导致安全性受损。 我强烈建议您调查各种可用的方法,然后选择一种适合您的需求。 基本上,我所看到的所有内容都可以轻松地为您提供此时所具有的功能:打开一个弹出窗口; 选择地点; 进入站点并填写用户名和密码。 密码管理器是一个非常重要的项目。 不是一个轻描淡写的项目,也不是一个没有安全问题经验的人的项目。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM