在 Xamarin.Forms (UWP) 项目中,我有一个 WebView
控制谁Source
使用 HTML 字符串创建,如下所示:
var webview = new Xamarin.Forms.WebView
{
Source = new HtmlWebViewSource
{
Html = "<html>....</html>"
}
};
HTML 包含可在 <body>
内动态生成 HTML 的 JavaScript。 。这在屏幕上完美呈现。这意味着 WebView 能够理解使用 JavaScript 创建的 DOM。太棒了。
但现在我需要解析一些生成的 HTML,但我似乎只能访问作为源传入的原始 HTML 字符串,而不是最终生成的 DOM。
有没有办法将 JavaScript 生成并由 WebView 理解的 DOM 转换为字符串,以便我可以解析(使用 HTML Agility Pack 或 AngleSharp 等库)并提取 HTML 的一些片段?这可以位于 Xamarin.Forms 或 UWP(我的目标平台)中。
注意: 完全公开(如果它有帮助,并避免指责这是 XY problem ),我最终试图解决打印具有多个页面的 WebView 的问题UWP - 对此的研究信息非常稀疏。我有一个适用于不是使用 JavaScript 动态生成的 HTML 的解决方案 - 基本上我提取了代表可打印页面的 HTML 部分,并将它们添加为单独的页面以进行打印和打印预览。但正如前面提到的,我似乎无法解析动态生成的内容。
最佳答案
我的第一个想法是使用 Eval
方法内置于 Xamarin.Forms 中,但后来我发现该方法不会返回任何内容,因此它仅适用于应用程序到 webview 的通信。
到目前为止,实现此目的最简单的方法是使用 WebView
的自定义版本控制:
public class ExtendedWebView : WebView
{
public delegate Task<string> GetHtmlRequestedHandler();
public event GetHtmlRequestedHandler GetHtmlRequested;
public async Task<string> GetHtmlAsync()
{
var handler = GetHtmlRequested;
if (handler != null)
{
return await handler.Invoke();
}
return null;
}
}
现在在 UWP 平台项目中创建一个自定义渲染器:
[assembly: ExportRenderer(typeof(ExtendedWebView), typeof(ExtendedWebViewRenderer))]
namespace App.UWP
{
public class ExtendedWebViewRenderer : WebViewRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<WebView> e)
{
base.OnElementChanged(e);
if (e.OldElement != null)
{
var ew = (e.OldElement as ExtendedWebView);
ew.GetHtmlRequested -= Ew_GetHtmlRequested;
}
if (e.NewElement != null)
{
var ew = (e.NewElement as ExtendedWebView);
ew.GetHtmlRequested += Ew_GetHtmlRequested;
}
}
private async Task<string> Ew_GetHtmlRequested()
{
return await Control.InvokeScriptAsync("eval", new string[] { "document.documentElement.outerHTML;" });
}
}
}
诀窍是我们调用 JavaScript eval
将从 Web View 返回 HTML 本身的函数。
您只需替换 WebView
在 XAML 中使用我们的 ExtendedWebView
并称之为 GetHtmlAsync
需要时使用方法。
我唯一不喜欢这个解决方案的是 event
有Task<string>
返回类型,这很奇怪。实际上已经有事件的返回类型是不寻常的。更好的解决方案是将属性放入自定义 EventArgs
native 控件将根据操作结果进行设置,但因为 InvokeScriptAsync
方法是异步的(并且非异步 InvokeScript
方法已过时,不应再使用),我们必须实现自定义 Task
当属性设置时,这将完成。这种方法在 UWP 中用于某些事件,它们使用“延迟”,这表示调用者只有在某些异步操作完成后事件才会完成。我将尝试寻找一些关于如何在自定义 View 的情况下调用 native 异步操作的权威答案:-)。
关于Xamarin.Forms (UWP) - 如何获取 WebView 的 DOM 作为 HTML 字符串?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49921779/