SwiftUI:WebKit 工具栏按钮没有做任何事情

SwiftUI: WebKit toolbar buttons not doing anything

这是一款使用 SwiftUI 和 WebKit 制作的适用于 macOS 的网络浏览器应用程序。在我的地址工具栏中,我有一些快捷按钮,例如刷新、返回、前进和一个指向 YouTube 的快捷 link 按钮。但是点击其中任何一个都没有任何反应。

内容视图

struct ContentView: View {
    @StateObject var webModel = WebStateModel()
    @State var text = ""
    
    var body: some View {
   //toolbar
            HStack{
                //Refresh Button
                 Button(action: {
                    WebView(webModel: webModel).refresh()    
                     })  {
                         Image("arrow.left.circle")
                     }
                 //Go Forward Button
                 Button{
                    WebView(webModel: webModel).goForward()

                 } label: {
                     Image("arrow.right.circle")
                     }              
                 //Youtube button
                 Button{
                    WebView(webModel: webModel).youtube()
                         } label: {
                             Image("house.circle")
                             }
            }
        VStack (spacing: 80) {
            TextField("Enter a URL", text: Binding(
                get: { text },
                set: { text = WebStateModel.stripHttps([=10=]) } ), onCommit: {
                    webModel.updateUrl(text)
                })
            WebView(webModel: webModel) //To display the loaded web page
        }
    }
}

WebView 的视图模型

class WebStateModel: ObservableObject {
    @Published var url: URL? = URL(string: "https://www.google.com")
    
    func updateUrl(_ str: String) {
        if let theUrl = URL(string: "https://" + WebStateModel.stripHttps(str)) {
            url = theUrl
        }
    }
    
    static func stripHttps(_ str: String) -> String {
        var txt = str.trim()
        if txt.starts(with: "https://") {
            txt = String(txt.dropFirst(8))
        }
        return txt
    }  
}

包含工具栏快捷功能的 WebView。

struct WebView: NSViewRepresentable {
    @ObservedObject var webModel: WebStateModel

    func makeNSView(context: Context) -> WKWebView {
        let wkWebview = WKWebView()
        if let theUrl = webModel.url {
            let request = URLRequest(url: theUrl, cachePolicy: .returnCacheDataElseLoad)
            wkWebview.load(request)
        }
        return wkWebview
    }

    func updateNSView(_ nsView: WKWebView, context: Context) {
        if let theUrl = webModel.url {
            let request = URLRequest(url: theUrl, cachePolicy: .returnCacheDataElseLoad)
            nsView.load(request)
        }
    }
func refresh() {
    let wkWebview = WKWebView()
    wkWebview.reload()
}


func goBack() {
    let wkWebview = WKWebView()
    guard wkWebview.canGoBack else { return }
    wkWebview.goBack()
}


func goForward() {
    let wkWebview = WKWebView()
    guard wkWebview.canGoForward else { return }
    wkWebview.goBack()
}

func youtube() {
    let wkWebview = WKWebView()
         wkWebview.load(URLRequest(url: (URL(string: "https://www.youtube.com")!)))
}
}

编辑我也试过了

func refresh() {
        WKWebView().reload()
    }

    func goBack() {
        guard WKWebView().canGoBack else { return }
        WKWebView().goBack()
    }


    func goForward() {
        guard WKWebView().canGoForward else { return }
        WKWebView().goForward()
    }

    func youtube() {
        WKWebView().load(URLRequest(url: (URL(string: "https://www.youtube.com")!)))
    }

单击工具栏中的任何按钮时,WebView 中没有任何反应。

如前所述,每次调用函数时都会创建一个新对象。 此外,您不应该尝试“return”按钮内的视图。 SwiftUI 是 基于不断变化的状态值。

改为这样做:

import SwiftUI
import WebKit

@main
struct TestApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}

class WebStateModel: ObservableObject {
    @Published var url: URL? = URL(string: "https://www.google.com")
    
    func updateUrl(_ str: String) {
        if let theUrl = URL(string: "https://" + WebStateModel.stripHttps(str)) {
            url = theUrl
        }
    }
    
    static func stripHttps(_ str: String) -> String {
        var txt = str.trim()
        if txt.starts(with: "https://") {
            txt = String(txt.dropFirst(8))
        }
        return txt
    }
}

struct WebView: NSViewRepresentable {
    @ObservedObject var webModel: WebStateModel
    
    let wkWebview = WKWebView()
    
    func makeNSView(context: Context) -> WKWebView {
        if let theUrl = webModel.url {
            let request = URLRequest(url: theUrl, cachePolicy: .returnCacheDataElseLoad)
            wkWebview.load(request)
        }
        return wkWebview
    }
    
    func updateNSView(_ nsView: WKWebView, context: Context) {
        if let theUrl = webModel.url {
            let request = URLRequest(url: theUrl, cachePolicy: .returnCacheDataElseLoad)
            nsView.load(request)
        }
    }
    func refresh() {
        wkWebview.reload()
    }
    
    func goBack() {
        guard wkWebview.canGoBack else { return }
        wkWebview.goBack()
    }
    
    func goForward() {
        guard wkWebview.canGoForward else { return }
        wkWebview.goForward()
    }
    
    func youtube() {
        wkWebview.load(URLRequest(url: (URL(string: "https://www.youtube.com")!)))
    }
}

extension String {
    func trim() -> String {
        return self.trimmingCharacters(in: .whitespacesAndNewlines)
    }
}

struct ContentView: View {
    @StateObject var webModel = WebStateModel()
    @State var text = ""
    
    @State var webView: WebView?
    
    var body: some View {
        VStack {
            //toolbar
            HStack{
                Button(action: { webView?.refresh() }) {
                    Image(systemName: "arrow.clockwise.circle")
                }
                Button(action: { webView?.goBack() }) {
                    Image(systemName: "arrow.left.circle")
                }
                Button(action: { webView?.goForward() }) {
                    Image(systemName: "arrow.right.circle")
                }
                Button(action: { webView?.youtube() }) {
                    Image(systemName: "house.circle")
                }
            }
            
            VStack (spacing: 80) {
                TextField("Enter a URL", text: Binding(
                    get: { text },
                    set: { text = WebStateModel.stripHttps([=10=]) } ), onCommit: {
                        webModel.updateUrl(text)
                    })
                webView
            }
        }
        .onAppear {
            webView = WebView(webModel: webModel)
        }
    }
    
}