Chrome 扩展程序:在 Angular 站点中准备好 DOM 后无法获取 DOM 元素

Chrome Extension: Unable to get DOM elements after DOM is ready in Angular sites

提问人:Yash Jain 提问时间:7/22/2020 最后编辑:NG.Yash Jain 更新时间:7/23/2020 访问量:369

问:

在像 https://sa.corp.saint-lukes.org/secureauth11/ 这样的基于 angularJS 的网站中,我需要使用 JavaScript 或 jQuery 获取页面中存在的所有密码元素。

$(“输入[type='密码']”) 当我们在 chrome 浏览器控制台中运行上述 jQuery 时,我们将得到两个字段。 一个字段对 UI 可见,另一个字段由于 angular 的“aria-hidden”属性而被隐藏。

但是,当我们在加载文档后运行上述jQuery时,我只得到一个隐藏的字段,因为网络中有多个调用在该特定时间处于待处理状态,该调用加载了第二个密码字段(对UI可见)。

在内容脚本下尝试了以下方法

  1. jQuery 和 javascript 中的 onLoadn 事件
$(window).on('load', function () {
         console.log($("input[type='password']"));
         //you will get only one field
    })
  1. ajaxStop:在内容脚本下不起作用
$(document).ajaxStop(function () {
    console.log($("input[type='password']"));
});

在上面的代码之前也尝试了$.ajaxSetup()

  1. jQuery ready 和 when 方法
$.when($.ready).then(function () {
    console.log($("input[type='password']"));
});

它不能在第一次缓存后工作,所以它有时会工作

  1. 在后台监视网络请求 .js

var numberOfRequests = 0
chrome.webRequest.onCompleted.addListener(
  function(details) {
    numberOfRequests--
    if (!numberOfRequests) {
      console.log('send message to content to fetch for input tags');
    }
    console.log(numberOfRequests);
  }, {
    urls: ["<all_urls>"]
  }
);

chrome.webRequest.onBeforeRequest.addListener(
  function(details) {
    numberOfRequests++
    console.log(numberOfRequests);
  }, {
    urls: ["<all_urls>"]
  }
);
它不起作用,因为当一个请求在触发下一个请求之前完成时,由于该 numberOfRequests 为 0。 无法在上面的代码中获取理想条件

  1. 突变观察者
    let observer = new MutationObserver((mutations) => {
        console.log(mutations);
    })

    observer.observe(document.body, {
        childList: true
        , subtree: true
    })

我们如何检查上面的代码中没有发生突变?

  1. 动态创建脚本并注入 DOM 内容 .js
    const script = document.createElement('script')

    script.setAttribute('src', chrome.extension.getURL('inject.js'))
    script.defer = true

    document.body.appendChild(script)

    script.onload = () => {
        console.log('script loaded');
    }

    const onMessage = ({ data }) => {
        console.log(data.message);
        console.log($("input[type='password']"));
        window.removeEventListener('message', onMessage)
    }
    window.addEventListener('message', onMessage)

注入 .js

; (function () {
    try {
        postMessage({
            message: 'dom_ready'
        })
    } catch (e) {
        // Fail quietly
        console.log(e);
    }
})()

manifest.json

...
  "background": {
    "scripts": [
      "background.js"
    ]
  },
  "content_scripts": [
    {
      "matches": [
        "<all_urls>"
      ],
      "run_at": "document_end",
      "js": [
        "jquery.js",
        "content.js"
      ]
    }
  ],
  "web_accessible_resources": [
    "inject.js"
  ]
...

毕竟,这找到了一种解决方案,即 settimeout 方法,这不是理想的情况,因为某些站点加载 DOM 的速度很快,并且会有延迟。

$(window).on('load', function () {
        setTimeout(() => {
            console.log($("input[type='password']"));
        }, 1800);
});

任何有解释的解决方案都是值得赞赏的。

javascript jquery angularjs dom google-chrome-extension

评论

0赞 wOxxOm 7/23/2020
由于超时方法有效,这意味着您可以使用 MutationObserver。但要正确操作:检查观察者回调中是否存在第二个输入。请注意,该节点通常位于其他容器中,因此与其检查 addedNodes,不如重新检查 $(“input[type='password']”)
0赞 Yash Jain 7/23/2020
@wOxxOm,它可以通过重新检查长度(即 2)或特定密码字段(使用 id 或 class)来适用于此特定站点。但是还有其他网站,如链接,只有一个密码字段,那么我必须检查这个网站(长度即 1)。我不知道一个页面中有多少个密码字段。除非我们有通用条件,否则重新检查不适用于所有站点。谢谢你的想法!!
1赞 wOxxOm 7/23/2020
然后就没有确切的解决方案,你必须使用 MutationObserver + 去抖动或超时。

答: 暂无答案