JS控制台与用户脚本中的不同行为,尝试操作iframed内容

Different behavior in JS console vs userscript, trying to manipulate iframed content

本文关键字:操作 内容 iframed 用户 控制台 脚本 JS      更新时间:2023-09-26

我正在尝试破解一个我不拥有但我希望改进的Web应用程序。

我想在DOM中的元素之前添加一些HTML,一个相同的域iframe。下面是来自控制台的示例:

jQ(".x-panel-body.x-panel-body-noheader").find("iframe").contents().find("body").find("#WorkspaceFrame").find(".x-panel-tbar.x-panel-tbar-noheader").find(".x-toolbar-right").find(".x-toolbar-right-ct").find("table");
[
<table cellspacing=​"0">​…​</table>, 
<table id=​"ext-comp-1046" cellspacing=​"0" class=​"x-btn   x-btn-text-icon" style=​"width:​ auto;​">​…​</table>​, 
<table cellspacing=​"0">​…​</table>​, 
<table cellspacing=​"0">​…​</table>​, 
<table id=​"ext-comp-1067" cellspacing=​"0" class=​"x-btn   x-btn-text-icon " style=​"width:​ auto;​">​…​</table>​, 
<table id=​"ext-comp-1068" cellspacing=​"0" class=​"x-btn   x-btn-text-icon " style=​"width:​ auto;​">​…​</table>​, 
<table id=​"ext-comp-1069" cellspacing=​"0" class=​"x-btn   x-btn-text-icon" style=​"width:​ auto;​">​…​</table>​, 
<table cellspacing=​"0">​…​</table>​, 
<table cellspacing=​"0">​…​</table>​, 
<table id=​"ext-comp-1253" cellspacing=​"0" class=​"x-btn   x-btn-text-icon x-item-disabled" style=​"width:​ auto;​">​…​</table>​, 
<table id=​"ext-comp-1254" cellspacing=​"0" class=​"x-btn   x-btn-text-icon" style=​"width:​ auto;​">​…​</table>​, 
<table cellspacing=​"0">​…​</table>​, 
<table cellspacing=​"0">​…​</table>​, 
<table id=​"ext-comp-1760" cellspacing=​"0" class=​"x-btn   x-btn-text-icon" style=​"width:​ auto;​">​…​</table>​, 
<table cellspacing=​"0">​…​</table>​
]

jQ是我的jQuery的名称(我不能使用$)。

所以基本上它从控制台工作,saveButton包含一个数组。这是我的脚本:

saveButton=jQ(".x-panel-body.x-panel-body-noheader").find("iframe").contents().find("body").find("#WorkspaceFrame").find(".x-panel-tbar.x-panel-tbar-noheader").find(".x-toolbar-right").find(".x-toolbar-right-ct").find("table");
console.log(saveButton);
jQ.each(saveButton, new function(i,v) { console.log("#"+i+": "+v); });

下面是控制台输出:

[prevObject: b.fn.b.init[0], context: document, selector: "body #WorkspaceFrame .x-panel-tbar.x-panel-tbar-noheader .x-toolbar-right .x-toolbar-right-ct table", jquery: "1.9.1", constructor: function…]
#undefined: undefined

所以saveButton是一个对象,而不是一个数组,这由失败的jQ.each确认。

我想拿一张桌子(它总是第三张)并在上面打电话给.before('<p>something</p>')。我试过saveButton[2].before('<p>HI</p>'),它不起作用。


这是在Zoltan答案中的提示之后的新尝试:

jQ(".x-panel-body.x-panel-body-noheader").find("iframe").contents().find("body").find("#WorkspaceFrame").find(".x-panel-tbar.x-panel-tbar-noheader").find(".x-toolbar-right").find(".x-toolbar-right-ct").find("table").eq(8).find(">:first-child").find(">:first-child").find(">:first-child").before('<td class="x-toolbar-cell"><button>Test</button></td>');

在控制台中键入此按钮可以正确添加我想要的按钮,但是JS代码中的同一行不起作用。什么给?

您可以使用 .eq(n) 获取选择中的第 n 个对象

saveButton.eq(n).before('<p>HI</p>')

saveButton[2] 不起作用,因为这样你得到一个没有 .before 函数的普通元素,但 .eq 返回 jQuery 包装的对象,你可以在它上面调用 jQuery 函数。

问题的根源也可能是您选择的内容位于 iframe 中。当您从控制台运行 JS 时,您处于外部窗口,您必须"单步"进入 iframe。但是JS可以在内部窗口中运行,从那里运行相同的查询不会找到任何iframe,因此不会向saveButton变量返回任何内容。

它在控制台中工作,因为您比用户脚本慢得多。 ;)  用户脚本在 iframe 完成加载之前很久就会触发,即使 iframe 不使用 AJAX 来设置内容也是如此。

解决此问题的最简单方法是调整您的用户脚本以直接在有问题的 iframe 上工作,这大大简化了。

但是,由于<iframe>似乎是同一域,因此您也可以使用 AJAX 页面所需的相同技术来处理该 iframe 内容。 在这种情况下,waitForKeyElements实用程序效果很好。

这是一个完整的脚本,应该适合您(但未经测试,因为我不知道目标页面)。 请注意,如果您运行的是Chrome,则需要安装Tampermonkey(无论如何都应该这样做)才能运行它。:

// ==UserScript==
// @name     _Interacting with iframed content
// @include  http://YOUR_SERVER.COM/YOUR_PATH/*
// @require  http://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js
// @require  https://gist.github.com/raw/2625891/waitForKeyElements.js
// @grant    GM_addStyle
// ==/UserScript==
/*- The @grant directive is needed to work around a design change
    introduced in GM 1.0.   It restores the sandbox.
*/
waitForKeyElements (
    //-- Double check this selector from the console...
    "#WorkspaceFrame .x-toolbar-right-ct table:eq(8) >:first-child >:first-child >:first-child",
    addButton, 
    false, 
    ".x-panel-body.x-panel-body-noheader iframe"
);
function addButton (jNode) {
    jNode.before ('<td class="x-toolbar-cell"><button class="gmMyButton">Test</button></td>');
}



作为奖励,您将像这样激活按钮。(需要延迟以避免竞争条件。

waitForKeyElements (
    "body", 
    addButtonHandler, 
    false, 
    ".x-panel-body.x-panel-body-noheader iframe"
);
function addButtonHandler (jNode) {
    jNode.on ("click", "button.gmMyButton", myButtonHandler);
}
function myButtonHandler (evt) {
    var btn = $(evt.target);
    console.log ("You just clicked button '" + btn.text() + "'.");
}