You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何检测WKWebView中AMP页面的滚动?代理方法失效的解决方案

哈哈,这个坑我踩过!AMP页面的滚动逻辑和普通网页不一样——它会在内部创建自己的滚动容器,根本不会用到WKWebView自带的UIScrollView,所以你绑定原生scrollView代理的方式自然就抓不到滚动事件了。给你分享几个实测有效的解决方案:

解决方案一:通过JS注入监听AMP内部滚动容器并与原生通信

这是最直接有效的方法,核心思路是用JavaScript找到AMP的内部滚动容器,监听它的滚动事件,再通过WKWebView的脚本消息机制把滚动数据传递给原生代码。

步骤1:配置WKWebView的脚本消息处理器

首先要让WKWebView能接收JS发来的消息,初始化时添加脚本处理器:

let webConfig = WKWebViewConfiguration()
let userContentController = WKUserContentController()
// 注册一个名为"ampScrollHandler"的消息处理器,后续JS会通过这个名字发消息
userContentController.add(self, name: "ampScrollHandler")
webConfig.userContentController = userContentController

// 初始化WKWebView
self.myWebView = WKWebView(frame: self.view.bounds, configuration: webConfig)
self.myWebView.scrollView.delegate = self // 保留原来的代理,兼容普通网页
self.view.addSubview(self.myWebView)

步骤2:在网页加载完成后注入监听JS

等AMP页面加载完成后,注入JS找到滚动容器并绑定滚动事件。推荐监听AMP官方的amp-ready事件,比固定延迟更靠谱:

func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
    // 注入的JS代码
    let scrollMonitorJS = """
    document.addEventListener('amp-ready', () => {
        // AMP页面的滚动容器标准类名是i-amphtml-scroll-container
        const scrollContainer = document.querySelector('.i-amphtml-scroll-container');
        if (scrollContainer) {
            // 监听滚动事件
            scrollContainer.addEventListener('scroll', () => {
                // 把滚动数据发给原生
                window.webkit.messageHandlers.ampScrollHandler.postMessage({
                    scrollTop: scrollContainer.scrollTop,
                    scrollHeight: scrollContainer.scrollHeight,
                    clientHeight: scrollContainer.clientHeight
                });
            });
        }
    });
    """
    
    // 执行JS注入
    webView.evaluateJavaScript(scrollMonitorJS) { result, error in
        if let error = error {
            print("AMP滚动监听JS注入失败:\(error.localizedDescription)")
        }
    }
}

步骤3:实现原生端的消息接收逻辑

让你的ViewController遵守WKScriptMessageHandler协议,接收JS发来的滚动数据:

extension YourViewController: WKScriptMessageHandler {
    func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
        guard message.name == "ampScrollHandler",
              let scrollData = message.body as? [String: Int] else {
            return
        }
        
        let scrollTop = scrollData["scrollTop"] ?? 0
        let scrollHeight = scrollData["scrollHeight"] ?? 0
        let clientHeight = scrollData["clientHeight"] ?? 0
        
        // 这里写你的滚动处理逻辑,比如判断是否滚动到底部
        let isAtBottom = (scrollTop + clientHeight) >= scrollHeight - 10 // 留10px的误差
        print("AMP页面滚动状态:scrollTop = \(scrollTop),是否到底部:\(isAtBottom)")
    }
}
补充说明
  • 为什么不用原生scrollView代理?因为AMP页面会把自己的内容放在固定高度的容器里,内部自己处理滚动,WKWebView的scrollView根本不会动,所以原生代理自然监听不到。
  • 如果遇到特殊AMP页面滚动容器类名不一样?可以用浏览器开发者工具查看页面结构,找到实际的滚动容器元素,调整JS里的选择器即可。

内容的提问来源于stack exchange,提问作者Randy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 06:32:58