javascript - 使用 WKWebView 通过 SwiftUI 从任何页面同步数据 - 但有更好的方法吗?
问题描述
在下面的代码中,我将 HTML 页面加载到 WKWebView 中,只是为了获取它们的第一个 H1 标记的内容。除了任何类型的页面在其第一个 H1 标记中呈现的内容之外,我不需要其他任何内容......
除了为此初始化 WKWebView 之外,是否还有更有效/更高效的方法?
(.frame(width: 0, height: 0)
修饰符也让我有点恼火)
import SwiftUI
import WebKit
import WebView /* add this Swift Package Dependency https://github.com/kylehickinson/SwiftUI-WebView */
struct ContentView: View {
@StateObject private var viewModel: ContentViewModel
init() {
let viewModel = ContentViewModel()
_viewModel = StateObject(wrappedValue: viewModel)
}
var body: some View {
VStack(spacing: 30) {
Button("load plain H1 tag") {
viewModel.webViewStore.webView.loadHTMLString("<h1>H1</h1>", baseURL: nil)
}
Button("load body where h1 is appended by JavaScript") {
viewModel.webViewStore.webView.loadHTMLString("<body></body><script>(function(){ let h1 = document.createElement('h1'); h1.textContent = 'H1 JavaScript'; document.body.appendChild(h1); })()</script>", baseURL: nil)
}
Button("load apple.com/iphone") {
viewModel.webViewStore.webView.load(URLRequest(url: URL(string: "https://apple.com/iphone")!))
}
Button("load hackingwithswift.com") {
viewModel.webViewStore.webView.load(URLRequest(url: URL(string: "https://hackingwithswift.com")!))
}
Group {
Text("the first H1 element on ")
+ Text(viewModel.webViewStore.webView.url?.description ?? "...").foregroundColor(.accentColor)
+ Text(" is")
}
.font(.subheadline)
Text(viewModel.h1)
.font(.largeTitle)
.foregroundColor(.green)
WebView(webView: viewModel.webViewStore.webView)
.frame(width: 0, height: 0)
}
}
}
class ContentViewModel: NSObject, WKScriptMessageHandler, ObservableObject {
@Published var h1 = "..."
@Published var webViewStore: WebViewStore
override init() {
let userContentController = WKUserContentController()
let configuration = WKWebViewConfiguration()
let userScript = WKUserScript(
source: """
function elementReady(selector) {
return new Promise((resolve, reject) => {
let el = document.querySelector(selector)
if (el) {
resolve(el)
}
new MutationObserver((mutationRecords, observer) => {
Array.from(document.querySelectorAll(selector)).forEach((element) => {
resolve(element)
observer.disconnect()
})
}).observe(document.documentElement, {
childList: true,
subtree: true,
})
})
}
elementReady("h1").then((titleElement) => {
window.webkit.messageHandlers.h1.postMessage(titleElement.textContent)
})
""",
injectionTime: .atDocumentStart,
forMainFrameOnly: false,
in: .defaultClient
)
userContentController.addUserScript(userScript)
configuration.userContentController = userContentController
let webView = WKWebView(frame: .zero, configuration: configuration)
webViewStore = WebViewStore(webView: webView)
super.init()
userContentController.add(self, contentWorld: .defaultClient, name: "h1")
}
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
if message.name == "h1" {
h1 = message.body as! String
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
解决方案
推荐阅读
- python - Python - 如何在 for 循环中打印 json 的内部键?
- c# - ServiceStack.OrmLite 使用错误的列定义创建表
- scala - 如何实现 CustomKeySerializer
- python - 当尝试在弹性搜索中进行批量更新时。我收到 403 错误?
- python - 如何让 docker 容器在主机内而不是容器内搜索文件?
- telethon - Telethon 无法再获取聊天实体
- python - 使用 genfromtxt 获取数据时遇到问题
- extjs - 如何在单击时显示包含两个单独工作的单选按钮的标题菜单
- java - 如何在不使用公共静态void main(String [] args)的情况下在vs代码中获取用户输入
- node.js - Chai:TypeError:无法读取未定义的属性“地址”