2017-09-01 37 views
5

我想在iframe的窗口上下文中運行一些javascript。現在我能想到做到這一點的唯一方法是注入一個腳本標籤:在框架窗口的上下文中運行代碼

myIframe = document.createElement('iframe'); 
myIframe.setAttribute('name', 'xyz123'); 
document.body.appendChild(myIframe); 

myIframe.contentWindow.document.write(` 
    <script> 
     console.log('The current window name is:', window.name); 
    </script> 
`); 

注:這是同一個域的iframe,沒有一個src,所以我必須完全進入contentWindow

對於我的用例來說,代碼運行正確的全局變量很重要; windowdocument等都應該作用於iframe本身。

有沒有其他辦法可以做到這一點?以上作品,但腳本需要在不同的域運行都具有不同的CSP的規則,這意味着增加了對隨機數/哈希等

支持是否有可能做這樣的事情:

myIframe.contentWindow.run(function() { 
    console.log('The current window name is:' window.name); 
}); 

我我試過myIframe.contentWindow.setTimeout,但似乎仍然在父窗口的上下文中運行代碼。

回答

2

也許將javascript分割爲從主窗口(我們稱之爲main.js)和iframe(我們稱之爲iframe.js)的部分。然後在iframe的src地方鏈接到iframe.jsiframe.html加載js文件(我不確定您是否可以直接包含來自src屬性的javascript)。

如果您將js加載到iframe中,請使用Calling a function inside an iframe from outside the iframe處的解決方案。

+0

感謝您的建議 - 但我使用的情況下,我需要能夠插入任意的JavaScript到框架中,這不一定是託管在任何地方 - 因此腳本標籤。 – bluepnume

2

您可以實際創建該run函數,然後將回調函數應用於this,這當然將是iframe上下文。然後,你可以通過使用this訪問iframe元素:

myIframe.contentWindow.run = function(fn) { 
    fn.apply(this); 
}; 

myIframe.contentWindow.run(function() { 
    console.log('(run) The current window name is:', this.window.name); 
}); 

控制檯輸出

(run) The current window name is: xyz123 

您可以檢查我在這裏的例子:http://zikro.gr/dbg/html/con-frame/

編輯

如果你想只需使用window而非this.window,那麼你就可以創建一個參數,內聯函數用他的名字window,然後只是通過this.window到像這樣的功能:

myIframe.contentWindow.run = function(fn) { 
    fn.call(this, this.window); 
}; 

myIframe.contentWindow.run(function(window) { 
    console.log('(run) The current window name is:', window.name); 
}); 

它仍然按預期工作。

+0

這是一個很好的例子 - 唯一的問題是,它改變了iframe中存在的任何函數的語義,以引用'this.window'而不是'window' - 但這絕對是最好的答案。遠。謝謝! – bluepnume

+0

@bluepnume不用客氣。我更新了我的答案,以使內聯函數具有可使用的名稱'window'的參數;它消除了使用'this.window'的需要。這將工作,除非你需要從一個特定的源明確應用整個內聯函數,然後將不可能具有該特定參數。 –

1
window.name='main window'; // just for debugging 
var myIframe = document.createElement('iframe'), frameScript = document.createElement('script'); 
document.body.appendChild(myIframe); 
frameScript.textContent = "window.top.name='topWindow';window.name = 'xyz123';function WhereAmI(){return(window.name);} window.parent.postMessage('frame_initialized', '*'); " 
myIframe.contentWindow.document.documentElement.appendChild(frameScript); 
function OnMessage(event) { 
    if(typeof event.data == 'string') switch(event.data) { 
    case 'frame_initialized': 
    myIframe.contentWindow.document.body.appendChild(document.createTextNode(myIframe.contentWindow.WhereAmI())); 
    console.log('Now running in', myIframe.contentWindow.WhereAmI()); 
    break; 
    } 
} 
window.addEventListener('message', OnMessage, false); 

經過Firefox和Chromium的測試。

而不是.textContent,您可以將.src應用於frameScript,以便腳本可以異步加載。然後你可以像上面那樣調用postMessage,或者調用回調函數來通知父窗口。

請注意,在您的原始代碼window.frameElement.name被初始化。你的腳本會詢問window.name。 FireFox自動將值複製到窗口,造成一些混淆。

+0

要改善此答案,我需要更好地瞭解您的情況。你有訪問這兩個域的HTML嗎?它應該只適用於你本地還是所有人?是否可以使用像GreaseMonkey這樣的腳本管理器? – gnblizz

+0

感謝您的建議,但我不確定window.postMessage會專門幫助我在框架中運行任意代碼 - 我需要一些方法在框架中添加一個消息監聽器,以使其工作,這會使我回到原來的問題。 – bluepnume

+0

要回答你的問題,這需要爲每個人工作,所以greasemonkey將無法正常工作。沒有第二個域 - iframe加載時沒有'src' – bluepnume

1

您需要異步加載腳本(即$.getScript()),然後在.contentWindow上調用它。我沒有測試,但這應該工作。

(function() { 

    var myIframe = document.createElement('iframe#iframe'): 

    var jsSnippet; 
    var iframeScript = function(url) { 
     script = document.createElement('script'), 
     scripts = document.getElementsByTagName('script')[0]; 
     script.src = url; 
     return jsSnippet = scripts.parentNode.insertBefore(script, scripts); 
    }; 

    myIframe.setAttribute('name', 'xyz123'): 
    myIframe.appendChild(jsSnippet); 
    document.body.appendChild(myIframe); 
    return document.getElementById('#iframe').contentWindow.iframeScript(); 
}) 

這兩個資源將是有益的,如果這個解決方案不起作用: https://plainjs.com/javascript/ajax/load-a-script-file-asynchronously-49/

Invoking JavaScript code in an iframe from the parent page

相關問題