将脚本元素添加到现有的TWebBrowser文档中

Mar*_*ynA 4 html javascript delphi twebbrowser

本周末由几个SO q提示,我决定看看我是否可以解决如何将Html元素中的一些javascript添加到TWebBrowser中加载的文档中.这样做,我遇到了一个奇怪的问题,也许有人可以解释.

这是我的Html文档

<html>
  <body>
  Something
  <br>
  <div id="forscript">some more text</div>
  </body>
</html>
Run Code Online (Sandbox Code Playgroud)

和我要添加的javascript元素

<script type="text/javascript" defer="false">{alert('hello');}</script>
Run Code Online (Sandbox Code Playgroud)

我作为Script参数传递给下面的AddScript().

这是我的代码(doc2是从WebBrowser获得的IHtmlDocument2):

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;
Run Code Online (Sandbox Code Playgroud)

这很好,但......

分配RHS上的Element.innerHTML的原因很简单,我发现如果RHS 包含脚本js,则js不会执行.我的问题是,为什么不,并且有一个更简单的替代方案,就像在某种程度上在代码中创建一个IHtmlScriptElement并将其插入DOM?显然,我简单易懂的解决方法只是在元素已经包含的文本前面添加,但我有点难以相信实际知道他们正在做什么的人会发现必要的.

FWIW#1:我尝试使用Element.insertAdjacentHtml来添加脚本但是得到了与我刚刚描述的相同的行为,就需要在脚本之外插入一些东西来获取脚本来执行时,所以我是想知道是否与在对其进行更改后如何处理DOM有关.

FWIW#2:我使用了Element.innerHtml路由,因为TWebBrowser/MSHTML.Pas拒绝了我在代码中创建IHtmlScriptElement的尝试; AFAICS,试图在MSHTML.Pas中使用任何CohtmlXXXElement例程引发"类未注册"例外,这似乎证实了我在这个教区的@kobik某处发现的评论.

(顺便说一句,在Win7 64位上使用D7 + IE11)

who*_*ddy 6

这是一个如何使用的完整示例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.
Run Code Online (Sandbox Code Playgroud)