更改页面 javascript 代码 (TamperMonkey) 以将键盘敲击发送到父级 DOM

Change page javascript code (TamperMonkey) to send keyboard strokes to the parent DOM

我有一个使用 TradingView 小部件的页面,您可以在其中键入键盘上的任意键以触发交易品种搜索。我使用 Chrome 的调试器来设置断点并确切地知道是哪一行代码执行的。我希望将按键事件冒泡到一般 DOM 由我自己的自定义函数处理。

怎么做?任何示例代码将不胜感激。这是来自 TradingView 的代码片段('t' 是关键事件):

            a || (o.handle = a = function(t) {
                return s === Te || t && Te.event.triggered === t.type ? s : Te.event.dispatch.apply(a.elem, arguments)
            }

因此,我想将该键事件发送到我自己的函数,而不是 return 语句。此代码所在的完整 TradingView 代码:https://static.bitmex.com/assets/tradingView/static/tv-chart.min-6ce28e05fd34b9cf06a4e63b29980a72.js

与其更改页面代码(这是可能的,但可能很乏味),不如考虑在 捕获 阶段将您自己的侦听器更改为 运行,而不是冒泡阶段。例如,而不是

document.body.addEventListener('keypress', fn);

document.body.addEventListener('keypress', fn, true);

它会 运行 在事件冒泡到内部元素之前。

如果页面在内部元素上的侦听器需要在您的 fn 运行 之前完成,您可以在小 setTimeout 之后调用 fn:

document.body.addEventListener('keypress', () => setTimeout(fn), true);

如果您还想阻止 运行ning 小部件的代码,请确保在您的捕获侦听器中调用 stopPropagation,这样事件就不会捕获到小部件:

const fn = (event) => {
  event.stopPropagation();
  // rest of code
};

如果您要向其发送按键事件的容器位于 iframe 中,由于安全问题,父级 window 根本看不到该事件。

大多数 页面上,您可以使用 postMessage 将事件传达给家长,例如:

// ==UserScript==
// @name             0 New Userscript
// @include          https://www.bitmex.com/app/trade/XBTUSD
// @include          https://static.bitmex.com/chartEmbed*
// @grant            GM_getValue
// @run-at document-start
// ==/UserScript==

if (window.location.host === 'www.bitmex.com') {
  const mainFn = () => {
    console.log('b');
  };
  // We're on the top level
  const keydown = (e) => {
    e.stopPropagation();
    if (!e.altKey && e.key === 'b') {
      mainFn();
    }
  };
  window.addEventListener('keydown', keydown, true);
  window.addEventListener('message', (e) => {
    if (e.origin === 'https://static.bitmex.com' && e.data === 'keydown inside iframe') {
      mainFn();
    }
  });
} else {
  // We're in the iframe
  // When a keypress is detected, message the parent window
  const keydown = (e) => {
    console.log('iframe kd');
    e.stopPropagation();
    if (!e.altKey && e.key === 'b') {
      window.top.postMessage('keydown inside iframe', '*');
    }
  };
  window.addEventListener('click', keydown, true);
}

@run-at document-start 是必需的,因为 iframe 有一个 forbids userscripts without it 来自 运行ning 的 CSP。

但不幸的是,还有另一个问题:在这种特殊情况下,iframe window also 在用户脚本有机会之前在页面加载时覆盖 EventTarget.prototype.addEventListener到 运行。虽然您可以 通常 使用 // @run-at document-start 来确保在页面脚本覆盖变量之前保存对变量的引用,但这在 iframe 中是不可能的; Chrome iframe 中的用户脚本不能 运行 在页面加载的最开始。

如果不引用 EventTarget.addEventListener(或 EventTarget.prototype.onclickEventTarget.prototype.onkeydown 设置器等),则无法访问注册用户的浏览器级别 API动作。

我认为在 Tampermonkey 中找不到您要找的东西。