从SwiftUI按钮调用valuateJavascript [英] Call evaluateJavascript from a SwiftUI button

查看:0
本文介绍了从SwiftUI按钮调用valuateJavascript的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设您有以下WKWebView实现:

import Combine
import SwiftUI
import WebKit

class WebViewData: ObservableObject {
    @Published var parsedText: NSAttributedString? = nil

    var isInit = false
    var shouldUpdateView = true
}

struct WebView: UIViewRepresentable {
    let text: String
    @ObservedObject var data: WebViewData

    func makeUIView(context: Context) -> WKWebView {
        context.coordinator.view.navigationDelegate = context.coordinator
        return context.coordinator.view
    }

    func updateUIView(_ uiView: WKWebView, context: Context) {
        guard data.shouldUpdateView else {
            data.shouldUpdateView = false
            return
        }

        let html = """
            <html>
                <head>
                    <meta charset="UTF-8" />
                    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
                </head>
                <body>
                    (text)

                <script>
                    let isScrolling = false;
                    let timer;

                    function toggleScrolling() {
                        if(!isScrolling) {
                            timer = setInterval(function() {
                                window.scrollBy(0, 1);
                            }, (80 / autoScrollVelocity));
                        } else {
                            clearInterval(timer)
                        }

                        isScrolling = !isScrolling;
                    }
                </script>
                </body>
            </html>
        """

        uiView.loadHTMLString(html, baseURL: nil)
    }

    func makeCoordinator() -> WebViewCoordinator {
        return WebViewCoordinator(view: self)
    }
}

class WebViewCoordinator: NSObject, WKNavigationDelegate {
    let view: WebView

    init(view: WebView) {
        self.view = view

        super.init()
    }

    func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
        DispatchQueue.main.async {
            if !self.view.data.isInit {
                self.view.data.isInit = true
                // useless text parsing here...
            }
        }
    }
}

在此视图中

import SwiftUI

struct ReadingView: View {
    @ObservedObject var webViewData = WebViewData()
    private let text: String

    init(text: String?) {
        self.text = text ?? "Sorry, this reading is empty"
    }

    var body: some View {
        VStack {
            Button("Auto scroll") {
                ??????
            }
            WebView(title: self.title, text: self.text, data: self.webViewData)
        }
        .onReceive(self.webViewData.$parsedText, perform: { parsedText in
            if let parsedText = parsedText {
               print(parsedText)
            }
        })
    }
}
现在,在标签为Auto scroll的按钮中,如何调用htmltoggleScrolling()中的Java脚本(或在必要时在WKUserScript中移动此代码)?我在这里完全迷路了。

提前感谢您的建议

推荐答案

我将解决问题本身(从SwiftUI按钮调用evaluateJavascript),而不一定是Java脚本本身(您的toggleScrolling函数),我还没有测试过。

我认为这是使用Combine(这意味着您必须确保在文件顶部import Combine)通过您已设置的ObservableObject在视图之间传递消息的绝佳机会。

这是最后的代码(我不得不对原始代码做了一些无法编译的小改动):


class WebViewData: ObservableObject {
    @Published var parsedText: NSAttributedString? = nil

    var functionCaller = PassthroughSubject<Void,Never>()
    
    var isInit = false
    var shouldUpdateView = true
}

struct WebView: UIViewRepresentable {
    let text: String
    @StateObject var data: WebViewData

    func makeUIView(context: Context) -> WKWebView {
        let webview = WKWebView()
        webview.navigationDelegate = context.coordinator
        return webview
    }

    func updateUIView(_ uiView: WKWebView, context: Context) {
        guard data.shouldUpdateView else {
            data.shouldUpdateView = false
            return
        }

        context.coordinator.tieFunctionCaller(data: data)
        context.coordinator.webView = uiView
        
        let html = """
            <html>
                <head>
                    <meta charset="UTF-8" />
                    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
                </head>
                <body>
                    (text)

                <script>
                    function doAlert() { document.body.innerHTML += "hi"; }
                </script>
                </body>
            </html>
        """

        uiView.loadHTMLString(html, baseURL: nil)
    }

    func makeCoordinator() -> WebViewCoordinator {
        return WebViewCoordinator(view: self)
    }
}

class WebViewCoordinator: NSObject, WKNavigationDelegate {
    var parent: WebView
    var webView: WKWebView? = nil

    private var cancellable : AnyCancellable?
    
    init(view: WebView) {
        self.parent = view
        super.init()
    }
    
    func tieFunctionCaller(data: WebViewData) {
        cancellable = data.functionCaller.sink(receiveValue: { _ in
            self.webView?.evaluateJavaScript("doAlert()")
        })
    }

    func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
        DispatchQueue.main.async {
            if !self.parent.data.isInit {
                self.parent.data.isInit = true
                // useless text parsing here...
            }
        }
    }
}


struct ReadingView: View {
    @StateObject var webViewData = WebViewData()
    var text : String

    init(text: String?) {
        self.text = text ?? "Sorry, this reading is empty"
    }

    var body: some View {
        VStack {
            Button("Call javascript") {
                webViewData.functionCaller.send()
            }
            WebView(text: text, data: webViewData)
        }
        .onReceive(webViewData.$parsedText, perform: { parsedText in
            if let parsedText = parsedText {
               print(parsedText)
            }
        })
    }
}

发生了什么?

  1. WebViewData上有一个PassthroughSubject不接受用于将信号从SwiftUI视图发送到WebViewCoordinator的实际值(它只接受Void)。

  2. WebViewCoordinator订阅该发布者并运行evaluateJavasscript。为此,它必须引用WKWebView,您可以看到我在updateUIView

    中传递了它
  3. 您实际上没有在makeUIView中返回WKWebView(或者您确实返回了,但问题的简化代码有点损坏了它)

这篇关于从SwiftUI按钮调用valuateJavascript的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆