【问题标题】:Xamarin.Forms (UWP) - How Can I Get a WebView's DOM as an HTML String?Xamarin.Forms (UWP) - 如何获取 WebView 的 DOM 作为 HTML 字符串?
【发布时间】:2018-09-29 23:58:01
【问题描述】:

在 Xamarin.Forms (UWP) 项目中,我有一个 WebView 控件,其 Source 是使用 HTML 字符串创建的,如下所示:

var webview = new Xamarin.Forms.WebView
{
    Source = new HtmlWebViewSource
    {
        Html = "<html>....</html>"
    }
};

HTML 包含在 &lt;body&gt; 中动态生成 HTML 的 JavaScript。这完美地呈现在屏幕上。这意味着 WebView 了解使用 JavaScript 创建的 DOM。太好了。

但现在我需要解析一些生成的 HTML,但我似乎只能访问作为 Source 传入的原始 HTML 字符串,而不是最终生成的 DOM。

有没有办法将 JavaScript 生成并被 WebView 理解的 DOM 转换为字符串,以便我可以解析(使用 HTML Agility Pack 或 AngleSharp 之类的库)并提取 HTML 的一些片段?这可以在 Xamarin.Forms 或 UWP(我的目标平台)中。

注意:完全公开(以防万一,并避免指责这是XY problem),我最终试图解决打印带有多个页面的WebView的问题UWP - 对此的研究得到了非常稀少的信息。我有一个适用于不是用 JavaScript 动态生成的 HTML 的解决方案 - 基本上我正在提取代表可打印页面的 HTML 部分,并将这些作为单独的页面添加为打印和打印预览。但如前所述,我似乎无法解析动态生成的内容。

【问题讨论】:

    标签: xamarin webview xamarin.forms uwp xamarin.uwp


    【解决方案1】:

    我的第一个想法是使用 Xamarin.Forms 中内置的 Eval 方法,但后来我发现该方法不返回任何内容,因此它仅适用于 app-to-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 视图返回 HTML 本身。

    您只需将 XAML 中的 WebView 替换为我们的 ExtendedWebView 并在需要时调用其 GetHtmlAsync 方法。

    我唯一不喜欢这个解决方案的是eventTask&lt;string&gt; 返回类型,这很奇怪。实际上已经有一个事件返回类型是不寻常的。更好的解决方案是将属性放在自定义EventArgs 中,本机控件将使用操作结果设置该属性,但是因为InvokeScriptAsync 方法是异步的(并且非异步InvokeScript 方法已过时并且不应该不再使用)我们必须实现一个自定义的Task,它会在设置属性时完成。这种方法在 UWP 中用于一些事件,它们使用“延迟”,它表示调用者只有在某些异步操作完成后事件才会完成。我将尝试寻找一些关于在自定义视图的情况下应如何实现调用本机异步操作的权威答案:-)。

    【讨论】:

    • 好主意!但是问题 - 当在平台代码中调用Ew_GetHtmlRequested 时,我们能否确定 DOM 内容已完全加载?有一个 Control.DOMContentLoaded 事件 - 我们应该以某种方式合并它吗?
    猜你喜欢
    • 2012-03-04
    • 2011-07-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-01-31
    • 1970-01-01
    • 2011-07-12
    • 1970-01-01
    相关资源
    最近更新 更多