从SwiftUI按钮调用valuateJavascript [英] Call evaluateJavascript from a SwiftUI button
本文介绍了从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)
}
})
}
}
发生了什么?
WebViewData
上有一个PassthroughSubject
不接受用于将信号从SwiftUI视图发送到WebViewCoordinator
的实际值(它只接受Void
)。WebViewCoordinator
订阅该发布者并运行evaluateJavasscript
。为此,它必须引用WKWebView
,您可以看到我在updateUIView
中传递了它您实际上没有在
makeUIView
中返回WKWebView
(或者您确实返回了,但问题的简化代码有点损坏了它)
这篇关于从SwiftUI按钮调用valuateJavascript的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!
查看全文