2014-11-23 82 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

相关问题