如何修改或覆盖Mac上WKWebView的上下文菜单?

Jus*_*ael 17 macos osx-yosemite wkwebview

WKWebView在Mac OS X应用程序中使用了一个.我想覆盖当用户Control+点击或右键单击时出现的上下文菜单WKWebView,但我找不到实现此目的的方法.

应该注意的是,上下文菜单根据WKWebView的状态以及调用上下文菜单时鼠标下的元素而变化.例如,当鼠标位于内容的"空"部分上方时,上下文菜单只有一个"重新加载"项,而右键单击链接则显示"打开链接","在新窗口中打开链接"选项,以及等等.如果可能的话,对这些不同的菜单进行精细控制会很有帮助.

较旧的WebUIDelegate提供了- webView:contextMenuItemsForElement:defaultMenuItems: 允许您自定义WebView实例的上下文菜单的方法; 我基本上正在寻找这种方法的模拟WKWebView,或者以任何方式复制功能.

Ken*_*per 18

您可以通过截取contextmenujavascript中的事件,通过scriptMessageHandler将事件报告回OSX容器,然后从OSX弹出菜单来完成此操作.您可以通过脚本消息的正文字段返回上下文以显示相应的菜单,或者为每个菜单使用不同的处理程序.

在Objective C中设置回调处理程序:

WKUserContentController *contentController = [[WKUserContentController alloc]init];
[contentController addScriptMessageHandler:self name:@"callbackHandler"];
config.userContentController = contentController;
self.mainWebView = [[WKWebView alloc] initWithFrame:self.view.frame configuration:config];
Run Code Online (Sandbox Code Playgroud)

使用jquery的Javascript代码:

$(nodeId).on("contextmenu", function (evt) {
   window.webkit.messageHandlers.callbackHandler.postMessage({body: "..."});
   evt.preventDefault();
});
Run Code Online (Sandbox Code Playgroud)

从目标C回应它:

-(void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message
{
    if ([message.name isEqualToString:@"callbackHandler"]) {
      [self popupMenu:message.body];
    }
}

-(void)popupMenu:(NSString *)context {
    NSMenu *theMenu = [[NSMenu alloc] initWithTitle:@"Context Menu"];
    [theMenu insertItemWithTitle:@"Beep" action:@selector(beep:) keyEquivalent:@"" atIndex:0];
    [theMenu insertItemWithTitle:@"Honk" action:@selector(honk:) keyEquivalent:@"" atIndex:1];
    [theMenu popUpMenuPositioningItem:theMenu.itemArray[0] atLocation:NSPointFromCGPoint(CGPointMake(0,0)) inView:self.view];
}

-(void)beep:(id)val {
    NSLog(@"got beep %@", val);
}

-(void)honk:(id)val {
    NSLog(@"got honk %@", val);
}
Run Code Online (Sandbox Code Playgroud)

  • 在iOS的"WKWebView"上,`contextmenu`处理程序在长按时不会被调用. (2认同)

Ely*_*Ely 11

您可以通过继承WKWebView类并执行willOpenMenu方法来拦截WKWebView类的上下文菜单项,如下所示:

class MyWebView: WKWebView {

    override func willOpenMenu(_ menu: NSMenu, with event: NSEvent) {
        for menuItem in menu.items {
            if  menuItem.identifier?.rawValue == "WKMenuItemIdentifierDownloadImage" ||
                menuItem.identifier?.rawValue == "WKMenuItemIdentifierDownloadLinkedFile" {
                menuItem.action = #selector(menuClick(_:))
                menuItem.target = self
            }
        }
    }

    @objc func menuClick(_ sender: AnyObject) {
        if let menuItem = sender as? NSMenuItem {
            Swift.print("Menu \(menuItem.title) clicked")
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

除此之外,您还可以简单地隐藏菜单项 menuItem.isHidden = true

检测所选菜单项是一回事,但知道用户在WKWebView控件中实际点击了什么是下一个挑战:)

也可以向menu.items阵列添加新的菜单项.

  • 我认为这是最好的答案,使用本机 API 而不是基于 JavaScript 的 hack。 (3认同)
  • 这非常有帮助,在这种情况下我如何获得右键单击的网址。帮助将不胜感激。 (2认同)