【问题标题】:Is there a bug with using InnerHTML inside a UIWebView within a native iPhone application?在原生 iPhone 应用程序的 UIWebView 中使用 InnerHTML 是否存在错误?
【发布时间】:2011-04-13 12:51:32
【问题描述】:

我有一个相当大的 HTML/JS/CSS 应用程序,在 iPhone 上通过 Safari 作为 Web 应用程序运行时效果很好。

当在原生 iPhone 应用程序中的 UIWebView 中运行相同的应用程序时,在 jQuery 中调用以创建 HTML 片段会静默失败(即:$("<div>HELLO WORLD</div>"); 不会创建元素。

我在干净的 jQuery 方法中找到了以下等效代码 sn-p:

var div = document.createElement(“div”); div.innerHTML = “<div>HELLO WORLD</div>”;

当我查看div.outerHTML 时,我看到了 &lt;div&gt;/&lt;div&gt;

div.innerHTML 返回一个空字符串。

这似乎不是 jQuery 问题,也不是 100% 发生的。我一直无法找到模式,但在某些情况下,它会连续工作 2-3 次,有时如果连续失败 5-6 次。这似乎只在 Objective-C 应用程序的 UIWebView 内运行应用程序时出现。此外,我只在运行 iOS 4.2 的实际设备上看到过这个,而不是模拟器。

有没有人遇到过类似的情况?有人解决了吗?

【问题讨论】:

    标签: javascript iphone jquery uiwebview


    【解决方案1】:

    我也有这个问题。当手机的 CPU 非常繁忙(比如 100%)时会发生这种情况。然后渲染引擎有时会忘记 innerHTML 设置。

    我的unify project中包含的解决方案是测试childNodes中是否有元素,否则再次应用。

    var target = document.createElement("div");
    var text = "<div>Hello World</div>";
    target.innerHTML = text;
    var self = this;
    self.__intervalHandle = window.setInterval(function() {
      target.innerHTML = text:
      if (target.firstChild) {
        window.clearInterval(self.__intervalHandle);
        self.__intervalHandle = null;
      }
    }, 100);
    

    这会强制渲染引擎将 innerHTML 应用到 DOM 并给渲染引擎一些时间(在本例中为 100 毫秒,在我们的测试中这是一个很好的值)。

    【讨论】:

    • 感谢 Sebastian - 这可能会让我走上正确的道路。这个调用实际上是在 jQuery 中,所以异步方法可能行不通,但很高兴知道发生了什么,我可能会考虑到这一点开发某种解决方法。
    【解决方案2】:

    嗯,Sebastian 发布的解决方案 [不是生产质量解决方案] 有效,但我无法确认 CPU 负载是否会导致此问题。我在 iOS 主机上产生了大量后台负载,无法重现此问题。

    经过进一步调查,渲染问题似乎是 iOS shell 取消导航的副作用。一旦导航被 iOS shell 取消,渲染引擎可能会认为不需要渲染更多 UI [基本上不会渲染任何东西一小段时间]。

    解决此问题的一种方法是将命令作为哈希 (#) 参数而不是 URL 发送到 iOS shell。这样 iOS shell 将获取命令并且不需要取消导航。这种方法似乎适用于下面的测试代码。因此,如果 window.location 设置为 location1,它会提示“At: 1”并且元素 e2 没有值。如果 window.location 设置为 location2,它会提示“At: 0”并且元素 e2 具有该值。

    @Kevin,您能否确认在发生此行为时您正在取消 iOS 主机上的导航。

    测试代码:

    Javascript:

        var location1 = "myApp://Test";
        var location2 = "#myApp://Test";
        $("#change").live("click", function (e) {
            var element = document.getElementById("e1");
            window.location = location1; var i = 0;            
            element.innerHTML = "At: " + i;
            window.__intervalHandle = window.setInterval(function () {
                var html = element.innerHTML;
                if (html) {
                     alert(html);
                    window.clearInterval(window.__intervalHandle);
                    window.__intervalHandle = null;
                } else {
                    element.innerHTML = "At: " + ++i;
                }
            }, 1);
            document.getElementById("e2").innerHTML = "Test";
        });
    

    iOS 伪代码:

    - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
    {
    NSURL* u = [ request URL];
    
    if( [[u scheme] compare:@"myapp" ] == NSOrderedSame) {
    { 
    return NO; // don’t navigate
    }
    return YES; // navigate
    }
    

    【讨论】:

    • 感谢 C. Ross - 我无法直接将失败的行为与我正在做的任何事情联系起来,但是当我返回应用程序并跟进时,我会将所有代码更改为您建议的内容在这个线程上。现在我发现如果我创建没有任何子元素的元素,然后在元素创建并附加到 DOM 之后添加子元素,它似乎工作正常。这需要一段时间,但似乎解决了问题。
    【解决方案3】:

    你应该看看http://blog.techno-barje.fr/post/2010/10/06/UIWebView-secrets-part3-How-to-properly-call-ObjectiveC-from-Javascript

    事实证明,取消导航作为-webView:shouldStartLoadWithRequest: 委托方法的一部分可能会导致innerHTML 出现问题。我更新了我们的 JS 代码以使用那篇文章中推荐的方法,并且我有一段时间没有看到 innerHTML 问题出现了。

    【讨论】:

      猜你喜欢
      • 2014-09-19
      • 2021-11-03
      • 2011-07-03
      • 2011-01-04
      • 1970-01-01
      • 2011-04-02
      • 1970-01-01
      • 2011-10-05
      • 1970-01-01
      相关资源
      最近更新 更多