【问题标题】:SwiftUI: WebKit is loading page continuously when typing urlSwiftUI:输入url时WebKit不断加载页面
【发布时间】:2021-07-31 09:15:23
【问题描述】:

这是我的 macOS 应用程序中的 URL 地址栏,可以正常使用此 TextField:

@State private var text = ""
@State private var site = "www.google.com/" //stored as two separate values so that WebKit isn't trying to continuously load a URL with every single keystroke. The "site" property is only updated once the user presses the return key.

var body: some View {

let webView = WebView(site: $site, text: $text)
    
        TextField("Enter a URL", text: $text, onCommit: {
                guard !text.isEmpty else {return}
                site = text
            })
             webView //To display the loaded web page
                    }

..但是在实现trim function 后,当用户将 URL 复制并粘贴到地址栏上时删除“https://”,WebKit 现在尝试在每次击键时不断加载 URL,我的应用程序停止工作。

@State private var text = ""
@State private var site = "www.google.com/"


var body: some View {

let webView = WebView(site: $site, text: $text)

    TextField("Enter a URL", text: Binding(
                    get: { text },
                               set: { newValue in
                                   if trim(newValue).starts(with: "https://") {
                                       text = String(trim(newValue).dropFirst(8))
                                   } else {
                                       text = newValue
                                   }
                               }), onCommit: {
                                
            guard !text.isEmpty else {return}
            site = text
        })
webView //To display the loaded web page

}

     func trim(_ str: String) -> String {
            return str.trimmingCharacters(in: .whitespacesAndNewlines)
        }
        

网页视图

struct WebView: NSViewRepresentable {
@Binding var site: String
private var webView: WKWebView


init(site: Binding<String>, text: Binding<String>) {
    self.webView = WKWebView()
    _site = site // 
    
}

func makeNSView(context: Context) -> WKWebView {
    return webView
}

func updateNSView(_ nsView: WKWebView, context: Context) {
    nsView.load(URLRequest(url: (URL(string: "https://" + site) ?? Bundle.main.url(forResource: "URLError", withExtension: "pdf")!)))
}

【问题讨论】:

  • 向我们展示 WebKit 尝试不断加载 url 的代码。
  • 当事情变得更复杂时,考虑使用 ViewModel 来处理整个数据相关的方面和逻辑,并让视图只呈现值。
  • @workingdog 添加了要发布的代码
  • 我看到了您发布的错误消息,但我没有看到 WebKit 尝试连续加载 url 的代码。我怀疑您为此使用“文本”,而您应该使用“站点”
  • @workingdog 我已经添加了我所有的代码。 WebView 与问题中的第一个文本字段完美配合。只有在尝试使用您之前在这篇文章中的第二个文本字段中向我展示的修剪功能之后,才会出现问题。

标签: swift swiftui webkit


【解决方案1】:

抱歉,删除了我之前的代码,因为它不适用于面向 macOS 10.15 的 Big Sur 11.3。

您可能会得到持续更新,因为“文本”在以下位置不断更新:

let webView = WebView(site: $site, text: $text)

删除您不使用的“文本”部分并相应地调整“WebView”初始化:

let webView = WebView(site: $site)

编辑 2:

为了完整起见,这是我在 macos 12 上运行的测试代码(因为这是我唯一拥有的) 但应该适用于 macOS 11.3。它使用 ObservableObject 来进行绑定。

import Foundation
import SwiftUI
import WebKit


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

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 ContentView: View {
    @StateObject var webModel = WebStateModel()
    @State var text = ""
    
    var body: some View {
        VStack (spacing: 80) {
            TextField("Enter a URL", text: Binding(
                get: { text },
                set: { text = WebStateModel.stripHttps($0) } ), onCommit: {
                    webModel.updateUrl(text)
                })
            WebView(webModel: webModel)
        }
    }
}

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)
        }
    }
}

【讨论】:

  • 我认为 OP 在 macOS 上,而不是在 iOS 上。 UIView/NSView。 :)
  • @workingdog 现在每次我在 URL 栏中输入一个字母时,整个页面都会刷新。
  • 对我来说效果很好,当我在 url 栏中输入字母时没有页面刷新。 url 仅在提交时更新。您使用的是什么系统并定位于哪个系统?
  • 我在 Big Sur 11.3 上,目标是 macOS 10.15
  • 更新了我的答案并为 macOS 添加了代码
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-10-02
  • 1970-01-01
相关资源
最近更新 更多