如何检测WKWebView中本地缓存图片的点击事件
解决WKWebView本地图片点击无响应的问题
我之前也碰到过一模一样的场景:WKWebView里加载的是本地缓存的<img>标签图片,既不是网络请求也没包裹<a>标签,点击时完全触发不了WKNavigationDelegate的decidePolicyFor方法,没法拦截事件来展示图片。这里给你两个亲测有效的解决方案:
方案一:JS+原生消息交互(推荐)
这是最稳定的方法,通过给网页注入JavaScript代码,监听所有图片的点击事件,再把图片的src传递给原生端处理。
步骤1:配置WKWebView的脚本消息处理器
先在初始化WKWebView时,注册一个用于接收图片点击消息的处理器:
import WebKit class YourViewController: UIViewController, WKScriptMessageHandler { var webView: WKWebView! override func viewDidLoad() { super.viewDidLoad() let config = WKWebViewConfiguration() let userContentController = WKUserContentController() // 注册消息处理器,名字要和JS里的对应上 userContentController.add(self, name: "imageClickHandler") config.userContentController = userContentController webView = WKWebView(frame: view.bounds, configuration: config) webView.navigationDelegate = self view.addSubview(webView) // 加载你的网页(本地或其他) let htmlPath = Bundle.main.path(forResource: "yourPage", ofType: "html")! let htmlURL = URL(fileURLWithPath: htmlPath) webView.loadFileURL(htmlURL, allowingReadAccessTo: htmlURL.deletingLastPathComponent()) } // 实现WKScriptMessageHandler协议,接收JS传来的消息 func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) { if message.name == "imageClickHandler", let imageSrc = message.body as? String { // 拿到图片的src后,在这里实现图片展示逻辑 print("点击了图片:\(imageSrc)") // 比如调用自定义的图片预览控制器 showImagePreview(with: imageSrc) } } // 自定义图片展示方法 private func showImagePreview(with src: String) { // 你的代码逻辑 } }
步骤2:注入JS监听图片点击
在网页加载完成后,注入JS代码。如果是静态网页,直接给所有<img>绑定点击事件;如果是动态加载的图片(比如下拉加载新图),用事件委托更稳妥:
extension YourViewController: WKNavigationDelegate { func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) { // 事件委托版JS:监听document的点击,判断目标是否为图片 let jsCode = """ document.addEventListener('click', function(e) { if (e.target.tagName.toLowerCase() === 'img') { window.webkit.messageHandlers.imageClickHandler.postMessage(e.target.src); } }); """ // 执行JS注入 webView.evaluateJavaScript(jsCode) { result, error in if let error = error { print("注入JS失败:\(error.localizedDescription)") } } } }
事件委托的好处是,不管网页后续新增多少图片,都能自动监听点击事件,不用重复注入JS。
方案二:通过触摸事件+JS获取点击元素
如果不想用消息交互,也可以通过原生的触摸事件,结合JS获取点击位置的元素:
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) { super.touchesEnded(touches, with: event) guard let touch = touches.first, touch.view === webView else { return } // 转换点击坐标为网页内的坐标(注意网页滚动的情况) let webPoint = touch.location(in: webView) let scrollOffset = webView.scrollView.contentOffset let adjustedPoint = CGPoint(x: webPoint.x, y: webPoint.y + scrollOffset.y) // 用JS获取该坐标下的元素 let js = """ (function() { var elem = document.elementFromPoint(\(adjustedPoint.x), \(adjustedPoint.y)); if (elem.tagName.toLowerCase() === 'img') { return elem.src; } return null; })(); """ webView.evaluateJavaScript(js) { result, error in if let imageSrc = result as? String { // 展示图片 self.showImagePreview(with: imageSrc) } } }
这个方法需要处理网页滚动的坐标转换,稳定性不如方案一,适合简单场景。
内容的提问来源于stack exchange,提问作者Ivan Cantarino
相关产品推荐
相关产品推荐

