【问题标题】:How to auto scroll a WebView after DOM changes in Cocoa / WebKit如何在 Cocoa / WebKit 中的 DOM 更改后自动滚动 WebView
【发布时间】:2013-01-03 23:48:57
【问题描述】:

我正在构建一个小型 Mac 应用程序,该应用程序通过 Web 套接字持续提供数据。处理完每个数据段后,数据显示在WebView 中。新数据从不替换WebView 中的任何数据,而是始终附加WebView 的内容中使用DOM 操作。下面的代码示例应该让您了解我在做什么。

DOMDocument *doc = self.webview.mainFrame.DOMDocument;
DOMHTMLElement *container = (DOMHTMLElement *)[doc createElement:@"div"];
NSString *html = [NSString stringWithFormat:@"... omitted for the sake of brevity ... "];
[container setInnerHTML:html];
[doc.body appendChild:container];

WebView 的呈现显然是异步发生的。有没有办法判断 DOM 操作何时完成并且内容已被绘制?我想使用[webview scrollToEndOfDocument:self] 之类的东西来实现自动滚动。监听 DOM 事件并没有帮助,因为它们似乎是在 DOM 被修改但在这些更改被呈现之前触发的。我目前使用的代码与以下类似

[self.webview.mainFrame.DOMDocument addEventListener:@"DOMSubtreeModified" listener:self useCapture:NO];

结合

- (void)handleEvent:(DOMEvent *)event
{
    [self.webview scrollToEndOfDocument:self];
}

这段代码的问题是滚动发生得太早了。我基本上总是落后一个数据段。我可以注册在绘制内容时触发的任何类型的回调/通知吗?

【问题讨论】:

  • 您可以尝试将网页视图中的所有 html 放到一个字符串中并进行修改。然后再次加载这个 html 字符串。
  • 虽然我知道这可行,但出于性能原因,我永远不会使用这种方法。 DOM 背后的部分想法是允许增量更改。一旦提交了此类更改,我只需要一种方法来获得通知。
  • WebKit 可以自行调度 DOM 突变事件,例如 DOMSubtreeModified。无法保证它们会及时发送,甚至根本无法发送。我认为您想要一个不使用突变事件的解决方案。我怀疑您需要延迟调用-scrollToEndOfDocument: 的原因是WebView 只会根据需要重新布局内容。如果您首先通过在与WebFrame 关联的WebDocumentView 实例上调用-layout 来强制它进行布局,我想您会得到您想要的结果。

标签: objective-c macos cocoa webkit


【解决方案1】:

使用计时器

可以使用NSTimer 实现自动滚动。该解决方案面临的挑战是确定何时禁用计时器以允许手动滚动。我无法做到后者。无论如何,这是使用计时器启用自动滚动的代码:

self.WebViewAutoScrollTimer = 
  [NSTimer scheduledTimerWithTimeInterval:1.0/30.0 
                                   target:self
                                 selector:@selector(scrollWebView:)
                                 userInfo:nil
                                  repeats:YES];

scrollWebView: 只是一个在 web 视图上调用 scrollToEndOfDocument: 的方法。

使用通知

Web 视图发出的NSViewFrameDidChangeNotification 列表只允许在帧大小更改的情况下滚动。这些变化发生在添加新内容时以及封装视图的大小发生变化时,例如窗口被调整大小。我的实现不区分这两种情况。

NSClipView *contentView = self.webView.enclosingScrollView.contentView;
[contentView setPostsFrameChangedNotifications:YES];
[[NSNotificationCenter defaultCenter] addObserverForName:NSViewFrameDidChangeNotification
                                                  object:contentView
                                                   queue:nil
                                              usingBlock:^(NSNotification *notification) {
                                                  [self.webView scrollToEndOfDocument:self];
                                              }];

注意: 重要的是您指示 web 视图的滚动视图的内容视图 - 考虑几次,它就会开始有意义 -在其帧大小更改时发布通知,因为 NSView 实例默认情况下不这样做。这是使用上面示例中的前两行代码完成的。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-30
    • 1970-01-01
    相关资源
    最近更新 更多