2014-11-23 85 views
3

本週末被幾個SO qs提示,我決定看看我是否可以制定如何在Html元素中添加一些javascript到載入TWebBrowser的文檔中。這樣做, 我遇到了一個怪胎,也許有人可以解釋。將腳本元素添加到現有的TWebBrowser文檔中

這裏是我的HTML文檔

<html> 
    <body> 
    Something 
    <br> 
    <div id="forscript">some more text</div> 
    </body> 
</html> 

和我的JavaScript元素我想給它添加

<script type="text/javascript" defer="false">{alert('hello');}</script> 

,我通過爲()下面的腳本參數AddScript。

這是我的代碼(從web瀏覽器獲得的IHTMLDocument2的DOC2):

procedure TForm1.AddScript(const Script : String); 
var 
    Element : IHtmlElement; 
    Doc3 : IHtmlDocument3; 
begin 
    Doc2.QueryInterface(IHtmlDocument3, Doc3); 
    Element := Doc3.GetElementByID('forscript'); 
    Element.innerHTML := Element.innerHTML + Script; 
end; 

這工作得很好,但是......

的原因Element.innerHTML上的在RHS轉讓只是,我發現 如果RHS包含只有腳本js,js不執行。我的問題是,爲什麼不,還有更簡單的替代方法,就像在代碼中創建IHtmlScriptElement並將其插入到DOM中一樣?很明顯,我的頭腦簡單的解決方法只是在元素已經包含的文本前加上一段文字,但我有一段時間很難相信那些真正知道自己在做什麼的人會發現這種必要性。

FWIW#1:我試着用Element.insertAdjacentHtml添加腳本,但得到正如我剛纔所描述的,在需要插入另外的東西劇本方面拿到劇本是相同的行爲執行,所以我想知道這是否與處理後的DOM如何處理有關。

FWIW#2:我已經使用了Element.innerHtml路線,因爲TWebBrowser/MSHTML.Pas抵制我 嘗試在代碼中創建一個IHtmlScriptElement; AFAICS試圖使用MSHTML.Pas中的任何 CohtmlXXXElement例程激發一個「Class not registered」異常,這似乎證實了我在該教區的@kobik某處發現的評論。

(順便說一句,在Win7的64位使用D7 + IE11)

回答

5

這裏完整示例如何使用IHtmlScriptElement。 Html在應用程序啓動時加載。 Button1Click下的代碼添加JavaScript以DOM和執行它:

unit u_frm_SO27091639; 

interface 

uses 
    Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, 
    Dialogs, StdCtrls, OleCtrls, SHDocVw, MsHtml, ActiveX; 

type 
    TForm1 = class(TForm) 
    WebBrowser1: TWebBrowser; 
    Button1: TButton; 
    procedure Button1Click(Sender: TObject); 
    procedure FormCreate(Sender: TObject); 
    private 
    { Private declarations } 
    public 
    { Public declarations } 
    end; 

var 
    Form1: TForm1; 

implementation 

{$R *.dfm} 

procedure LoadDocFromString(Webbrowser : TWebbrowser); 

var 
    Strm : TStringStream; 
    Adapter : TStreamAdapter; 

begin 
WebBrowser.Navigate('about:blank'); 
// warning - don't use this trick in production code, use the `OnDocumentComplete` event 
while WebBrowser.ReadyState <> READYSTATE_INTERACTIVE do 
    Application.ProcessMessages; 
// end of warning 
Strm := TStringStream.Create; 
try 
    Strm.WriteString('<html><body>Something<br></body></html>'); 
    Strm.Seek(0, 0); 
    Adapter := TStreamAdapter.Create(Strm); 
    (WebBrowser.Document as IPersistStreamInit).Load(Adapter) ; 
finally 
    Strm.Free; 
end; 
end; 

procedure TForm1.Button1Click(Sender: TObject); 

var 
    Doc2  : IHtmlDocument2; 
    Script : IHtmlDOMNode; 
    HTMLWindow: IHTMLWindow2; 

begin 
Doc2 := Webbrowser1.Document as IHtmlDocument2; 
if Assigned(Doc2.body) then 
    begin 
    Script := Doc2.createElement('script') as IHTMLDOMNode; 
    (Script as IHTMLScriptElement).text := 'function helloWorld() { alert("hello world!") }'; 
    (Doc2.body as IHtmlDomNode).appendChild(Script); 
    HTMLWindow := Doc2.parentWindow; 
    if Assigned(HTMLWindow) then 
    HTMLWindow.execScript('helloWorld()', 'JavaScript') 
    end; 
end; 

procedure TForm1.FormCreate(Sender: TObject); 
begin 
LoadDocFromString(Webbrowser1); 
end; 

end. 
+0

驚人。它是「Script:= Doc2.createElement('script')作爲IHTMLDOMNode;(腳本爲IHTMLScriptElement).text ...」我錯過了。一件令人頭痛的事情是,用我的代碼腳本立即執行,而這使用明確的HTMLWindow.execScript調用。我將閱讀一下,看看是否有一種方法可以避免這種需要... – MartynA 2014-11-23 19:01:29

+0

如果我理解正確,您希望從網頁執行腳本,而不是從Delphi執行腳本? – whosrdaddy 2014-11-23 19:03:39

+0

是的,我的意思是將它留給WebBrowser後面的DOM引擎thingie。 – MartynA 2014-11-23 19:05:10

相關問題