• 【uwp】浅谈China Daily 中划词翻译的实现


    学习uwp开发也有一段时间了,最近上架了一个小应用(China Daily),现在准备将开发中所学到的一些东西拿出来跟大家分享交流一下。

    先给出应用的下载链接:China Daily , 感兴趣的童鞋可以看一看。

    废话就扯到这里,接下来,我们来看看这个应用中的划词翻译功能是如何实现的(也顺带谈谈点击正文中的图片显示详情)。

    新闻的主体是放在一个WebView里面的,所以,说白了就是解决WebView的问题(JS通知后台C#以及C#调用JS)。

    1.XAML

    <WebView x:Name="webView"
             NavigationCompleted="webView_NavigationCompleted"
             ScriptNotify="webView_ScriptNotify"
             />

    2.添加对alert的监听

    private async void webView_NavigationCompleted(WebView sender, WebViewNavigationCompletedEventArgs args)
    {
        //检测alert
        var inject = WebViewUtil.RiseNotification();
    
        await webView.InvokeScriptAsync("eval", new List<string>() { inject });
    }
    public static string RiseNotification()
    {
        string func = @"window.alert = function(arg) {
                            window.external.notify(arg);
                        };";
        return func;
    }

    3.监听到alert时的处理

    private void webView_ScriptNotify(object sender, NotifyEventArgs e)
    {
        var data = e.Value.Trim();
    
        if (data.Contains("http://"))
        {
            // 判断点击的是图片
            LoadImage(data);
        }
        else
        {
            // 判断点击的是文本
            LoadTranslation(data);
        }
    }

    此处的data是WebView通过JS方法传递过来的信息。如果点击的是图片,则传递图片的url;如果点击(选中)的是文本,则把文本传递过来。

    当然,WebView会这么机智的将我们想要的信息准确的传递过来吗?答案是肯定的,前提是我们要告诉它应该怎么做。

    4.交给WebView的锦囊

    4.1 明确任务

    China Daily 接口没有直接返回完整的html,但它将主要的内容都交到了我们手里,而我们所需要完成的,就是把这些资源给组合起来,再交给WebView。

    4.2 前期准备

    public static int GetBaseFontSize() => DeviceUtils.IsMobile ? 32 : 14;
    
    public static int GetBaseLineHeight() => DeviceUtils.IsMobile ? 64 : 28;
    
    /// <summary>
    /// 内容样式
    /// </summary>
    /// <returns></returns>
    public static string GetContentCSS()
    {
        string commonStyle = "touch-action: pan-y; font-family:'微软雅黑';" + (DeviceUtils.IsMobile ? "padding:2px 19px 2px 19px;" : "text-align:justify;  padding:2px 16px 2px 5px;");
    
        string colorstyle = "background-color:#ffffff; color:#000000;" ;
    
        string webStyle = "body{" + commonStyle + colorstyle +
                          $"font-size:{GetBaseFontSize()}px; line-height:{GetBaseLineHeight()}px" +
                          "}";
        string css = "<style>" + webStyle + "</style>";
    
        return css;
    }
    /// <summary>
    /// JS方法
    /// </summary>
    /// <returns></returns>
    public static string GetContentJS()
    {
        string js = @"window.lastOriginData = '';
                      
                      function mouseUp (param) {
                          if(param == 'y') return;
                          if (window.getSelection) {
                              var str = window.getSelection().toString();
                              window.lastOriginData = str.trim();
                              alert(str);
                          }
                      };
                      function getImageUrl(url) {
                          alert(url);
                      }
                      window.onload = function () {
                          var as = document.getElementsByTagName('a');
                          for (var i = 0; i < as.length; i++) {
                              as[i].onclick = function (event) {
                                  window.external.notify(JSON.stringify({ 'type': 'HyperLink', 'content': this.href }));
                                  return false;
                              }
                          }
                      };";
    
        return js;
    }

    GetContentCSS方法只是用于给整段新闻添加一个样式,使布局看起来美观一点,大家不用太在意。

    可以关注下的是GetContentJS方法。小小的说明一下,window.onload部分不用太在意;mouseUp部分用于在光标离开的时候,通知后台C#用户所选中的文本;而getImageUrl方法则是用于传递所点击的图片的url。当然,接口给定的内容中一般来说不可能给出img的onclick事件,因此,这个部分也需要我们进行相关处理:

    private const string imgStyle = "style='max- 100%' onclick='getImageUrl(this.src)'";
    /// <summary>
    /// 处理新闻内容(主要是过滤Style和为图片添加点击事件)
    /// </summary>
    /// <param name="content"></param>
    /// <returns></returns>
    public static string UpdateContentStyle(string content)
    {
        if (string.IsNullOrEmpty(content))
            return null;
    
        // 正则匹配img,统一替换它的Style,并添加点击事件(此处该如何匹配还应视具体情况而定)
        var matches = Regex.Matches(content, @"<img[sS]*?(style='[sS]*?')[sS]*?/?>");
        List<string> list = new List<string>();
    
        if (matches.Count > 0)
            list.Add(matches[0].Groups[1].Value);
    
        for (int i = 1; i < matches.Count - 1; i++)
        {
            if (!list.Contains(matches[i].Groups[1].Value))
                list.Add(matches[i].Groups[1].Value);
        }
    
        foreach (var item in list)
        {
            content = content.Replace(item, imgStyle);
        }
    
        return content;
    }

    4.3 整合资源

    /// <summary>
    /// 将新闻主体部分拼凑成一段完整的html
    /// </summary>
    /// <returns></returns>
    public string ProcessNewsContent()
    {
        var newsContent = WebViewUtil.UpdateContentStyle(news.Content);
    
        string webContent = "<html><head>" + contentCSS + "<script>" + js + "</script>" + "</head>" + "<body><div onmouseup='mouseUp()'> " + newsContent + "</div>" + "</body></html>";
    
        return webContent;
    }

    简单说明一下,contentCSS就是上方GetContentCSS方法返回的结果,js是GetContentJS方法返回的结果,news则是用于展示的新闻,news.Content则是新闻内容,

    它的大概模样如下(截取部分):

    <p>
        <strong>Today three top economists look at the state of the global economy and give their outlooks for 2017.</strong>
    </p>
    <p>
        <img attachmentid=""232694"" src=""http://iosnews.chinadaily.com.cn/newsdata/news/201612/26/432220/picture_232694.jpg"" style='max- 100%' />
    </p>

    4.4 交货

    webView.NavigateToString(content);

    此处的content自然就是我们整合好的资源了(一段字符串)。

    5.存在的问题

    至此,关键的部分均已实现,让我们按照以上套路运行一番。(假设LoadImage和LoadTranslation方法都只是将JS传递过来的信息直接显示出来)

    我们发现,PC上正常运行无压力;而手机上却是另一番光景——选中文本的时候没有任何反应,取消选中的时候反倒是显示信息了。(尚未搞清楚是为何)

    因此,我采用了一个纠正措施,如下:

    /// <summary>
    /// 为wp修正文本选中问题
    /// </summary>
    public async void ProcessTextSelected4Phone(string text)
    {
        if (DeviceUtils.IsMobile)//wp上表现和电脑上不一样...
        {
            // 判断是否选中文本
            DataPackage dataPackage = await webView.CaptureSelectedContentToDataPackageAsync();
            if (dataPackage == null)// 表示未选中文本
            {
                LoadTranslation(null);// 隐藏翻译栏
                return;
            }
    
            var handleMouseUp = string.IsNullOrEmpty(text) ? false : true;
            await webView.InvokeScriptAsync("mouseUp", new[] { handleMouseUp ? "y" : "" });// 若参数为y,则不触发事件
        }
    }

    其实质就是在手机端,在正常的mouseUp触发基础上,通过代码主动多触发一次mouseUp,以达到修正目的。

    6.Demo

    https://files.cnblogs.com/files/lary/Demo.rar

    7.参考

    【WP8.1】WebView笔记:http://www.cnblogs.com/bomo/p/4320077.html

     

    初次写博客,多多包涵

    花开成景,花落成诗。不问花开几许,只问浅笑安然。(●'◡'●)

  • 相关阅读:
    突发!Gitee 图床,废了!
    基于Springboot工程使用手机连接电脑服务器
    vue方法挂载到window对象上
    数据库篇:mysql日志类型之 redo、undo、binlog
    技能篇:linux服务性能问题排查及jvm调优思路
    数据库篇:mysql事务原理之MVCC视图+锁
    数据库篇:mysql锁详解
    Linux日常
    从文件下载视角来理解Web API
    朴素贝叶斯算法
  • 原文地址:https://www.cnblogs.com/lary/p/6233493.html
Copyright © 2020-2023  润新知