WKWebView - 防止用户文本选择触发的自动滚动

ban*_*na1 9 html javascript css swift wkwebview

当用户执行点击并按住手势选择一个单词,然后将手指拖向屏幕的顶部或底部边缘时,页面会自动滚动以适应选择。

这是一个演示它的短片

我想在WKWebView.

这是我迄今为止尝试过的:

在bridge.jswebview 可访问的文件中:

var shouldAllowScrolling = true;

document.addEventListener('selectionchange', e => {
    shouldAllowScrolling = getSelectedText().length === 0;
    window.webkit.messageHandlers.selectionChangeHandler.postMessage(
        {
            shouldAllowScrolling: shouldAllowScrolling
        });
    console.log('allow scrolling = ', shouldAllowScrolling);
});
Run Code Online (Sandbox Code Playgroud)

然后在一个WKScriptMessageHandler实现中:

public func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage)
    {
        switch message.name
        {
        case "selectionChangeHandler":
            let params = paramsDictionary(fromMessageBody: message.body)
            let shouldEnableScrolling = params["shouldAllowScrolling"] as? Bool ?? true
            cell?.webView.scrollView.isScrollEnabled = shouldEnableScrolling
            cell?.webView.scrollView.isUserInteractionEnabled = shouldEnableScrolling // not together with the line above 
        default:
            fatalError("\(#function): received undefined message handler name: \(message.name)")
        }
    }
Run Code Online (Sandbox Code Playgroud)

同样,我尝试preventDefault()直接在 javascript 文件中为一堆事件调用该函数,即scrolland touchmove,如下所示:

document.addEventListener('touchmove', e => {
    if (!shouldAllowScrolling) {
        e.preventDefault()
    }
}, {passive: false});
Run Code Online (Sandbox Code Playgroud)

both methods successfully prevent scrolling when some text is selected but do not override the behavior described at the very top of my question.

我可以接受 Swift 和 JavaScript 或两者混合的解决方案。

ban*_*na1 7

我最终通过保存最后一个滚动位置并在适当的时候滚动到它来解决这个问题,如下所示:

var shouldAllowScrolling = true;
var lastSavedScrollLeft = 0;
var lastSavedScrollTop = 0;

function saveScrollPosition() {
    lastSavedScrollLeft = window.pageXOffset || document.documentElement.scrollLeft;
    lastSavedScrollTop = window.pageYOffset || document.documentElement.scrollTop;
}

document.addEventListener('touchstart', e => {
    saveScrollPosition();
});

document.addEventListener('touchend', () => {
    // enable scrolling when the user lifts their finger, to allow scrolling while text selection is still present
    shouldAllowScrolling = true;
});

document.addEventListener('scroll', e => {
    if (!shouldAllowScrolling) {
        window.scrollTo(lastSavedScrollLeft, lastSavedScrollTop);
    }
});

document.addEventListener('selectionchange', e => {
    shouldAllowScrolling = getSelectedText().length === 0;
});
Run Code Online (Sandbox Code Playgroud)

如果有人可以提供更优雅的解决方案来完全防止滚动,那么很乐意接受它。

编辑:

此解决方案可能会导致轻微抖动/抖动。

这可以通过在shouldAllowScrolling设置为 时本地禁用滚动来解决false,如下所示:

webView.scrollView.isScrollEnabled = false
Run Code Online (Sandbox Code Playgroud)