本文整理自网络,侵删。
以往一直用TWebBrowser 或者 C++ Builder 中的TCcpWebBrowser来写网页模拟操作这两个控件可以使用WebBrowser.OleObject.document、WebBrowser.Document As IHTMLDocument2来实现大部分的操作发现这两者都是依赖于IE内核,虽然可以设定IE 11内核,但是今年微软公布11月底停止更新了所以可以考虑使用微软推出的Edge浏览器
进入正题:
Delphi 10.4.1 新增的TEdgeBrowser控件研究了一下发现该控件似乎不再支持像TWebBrowser那样使用IHTMLDocument2方法了Google一下发现几乎没有资料可寻,在GW某个论坛看到说被其他方式代理了,翻了一下Edge类,在类中有这么一个方法:
/// <summary> /// Execute JavaScript code from the javascript parameter in the current top level document rendered in the /// WebView, even if ScriptEnabled is False /// </summary> procedure ExecuteScript(const JavaScript: string);
对应回调事件
当 ExecuteScript 执行完成后回调结果给 OnExecuteScript /// <summary> /// Event handler type for the OnExecuteScript event /// </summary> TExecuteScriptEvent = procedure (Sender: TCustomEdgeBrowser; AResult: HResult; const AResultObjectAsJson: string) of object;
OnExecuteScript 包含两个参数,AResult 返回状态,AResultObjectAsJson 返回数据经过测试发现,AResultObjectAsJson 默认回调过来的数据如果不是Json而是字符串,那么该字符串会被加上双引号,如 “button click success”,AResultObjectAsJson 的返回值经过测试,好像只返回最后一次被赋值的变量或被修改过的元素值
方法:下载WebView2的dll支持库放入程序目录下链接:https://pan.baidu.com/s/1ASnrkr8v893egwSoCVNcjg提取码:igjt
下载MicrosoftEdgeDev浏览器,安装好桌面会出现Microsoft Edge Dev图标链接:https://pan.baidu.com/s/1OrGtyYpNdM1ph5qNyHFU1Q提取码:acap
在这里插入图片描述
以上工作做好以后,即可进行开发了1.界面拖入EdgeBrowser控件2.在控件事件中双击OnExecuteScript创建一个回调事件3. EdgeBrowser1.ExecuteScript(‘你的JavaScript脚本’);
假定我们打开的页面有这样一个按钮:
<input class="class1" id="button1" type="text" value="">
那么在我的程序目录下写一个名为 test.js 的文件,保存格式为utf-8,用于修改网页input的value值。JavaScript代码如下:注意脚本不用加
<script></script>
,加了之后好像无法运行
var Result = null; //这个作为最后处理的结果返回值var item = document.getElementById(“button1”);item.velue = “123456”;//OnExecuteScript回调返回 AResultObjectAsJson 的值是 “123456”//如果加上这一条Result = “输入成功”;//那么 OnExecuteScript回调返回 AResultObjectAsJson 的值是 “输入成功”
<br>
变通一下,将这个脚本写成模板```javascript//用于向页面input元素输入值var Result = null;//这个作为最后处理的结果返回值var idName = "%s";//这个作为你要替换的元素IDvar mValue = "%s";//这个作为你要写入的值var item = document.getElementById(idName );if(item != null){item.focus();item.value = mValue;//这个就是最后OnExecuteScript返回的值,如果没有这一条,那么返回的应该是 item.value 的值Result = "set " + mValue + " success";//当然也可以返回json、整数Result = {"status":true, "text":"输入成功"};}//如果没有设定Result 的值,那么结果返回的肯定是你修改的值
定义一个函数用来加载js文件并格式化数据
function getJavaScript(ScriptPath:string; Args:array of string);var AList:TStringList;I:Integer;beginAlist:= TStringList.Create;Alist.LoadFromFile(ScriptPath, TEncoding.UTF8);for I := Low(Args) to High(Args) do begin //StringReplace函数 需要引用 System.SysUtils AList.Text := StringReplace(AList.Text, '%s', Args[I], []); end;Result:= AList.Text;AList.Free;end;
读取脚本并运行
procedure TForm1.Button1Click(Sender: TObject);var AText:string;beginAText:= getJavaScript('test.js', ['button1', '123456']);EdgeBrowser1.ExecuteScript(AText);end;
这样就可以方便的调用JavaScript脚本了需要注意的是EdgeBrowser1.ExecuteScript();不能在线程中调用,如果是匿名线程需这样
TThread.Synchronize(TThread.CurrentThread, procedurebeginEdgeBrowser1.ExecuteScript('你的脚本');end);
如果是线程,建议在当前单元定义一个全局变量,用于存放OnExecuteScript的返回值写一个线程函数用于运行并等待回调,回调一般执行失败AResultObjectAsJson 的值是null,成功则返回脚本中的值,我测试了一下这样效果很理想,期待有更好的解决办法
function TForm1.ExecJavaScript(AScript: string): string;begin ScriptResult:= '';//全局变量 TThread.Synchronize(TThread.CurrentThread, procedure begin EdgeBrowser1.ExecuteScript(AScript); end);
while not TThread.CheckTerminated do begin Sleep(50); if ScriptResult <> '' then break; end;
Result:= ScriptResult;end;
回调
procedure TForm1.EdgeBrowser1ExecuteScript(Sender: TCustomEdgeBrowser; AResult: HRESULT; const AResultObjectAsJson: string);begin ScriptResult:= AResultObjectAsJson;end;
线程中直接调用ExecJavaScript就可以了,可以循环执行,直到结果不为null线程中调用
Script1:= GetJavaScript('setElementValueById.js', ['J_payeeShowAccount', "123456789"]); while not TThread.CheckTerminated do begin Sleep(50); if ExecJavaScript(Script1) <> 'null' then break; end;
目前好像就只能这样了,流畅度好像比IE要舒服。。。。期待更好的方法。。。。建议使用Json作为返回值,相对来说复杂点,个人比较懒,哈哈。。
来源:https://blog.csdn.net/zhou752947/article/details/109542365
相关阅读 >>
Delphi tstringlist的delimitedtext的空格问题
Delphi 如何在tmemo,tedit或trichedit中获得插入符的位置
Delphi中使用词霸2005的动态库xdictgrb.dll实现屏幕取词
Delphi 在firemonkey应用程序中设置application.title
更多相关阅读请进入《Delphi》频道 >>