簡體   English   中英

更干凈的方法掛接到網頁的window.onload嗎?

[英]Cleaner way to hook into the window.onload of a web page?

我正在Swift中構建一個小型iOS應用程序,並且使用了WKWebView 我要實現的目標是在網頁完全呈現后得到通知。 WKWebView的一個已知問題是其加載通知均無效

但是,這種方法似乎可行,其想法是掛接到Javascript中的window.onload函數並從那里通知Swift。 但是,我也在這里發現了一個問題。 如果我使用JQuery,則在某些頁面中顯然不會發生回調,因為網頁已經定義了window.onload 如果我使用純Javascript方式,則某些網頁會中斷,即它們顯然根本不會加載,因為我覆蓋了window.onload

// using JQuery, this function never get called for web pages that do window.onload = 
$(window).load(function() { 
    window.webkit.messageHandlers.callbackHandler.postMessage(
        JSON.stringify({body: "window finished loading"}));
});
// works always but breaks web pages that use window.onload
window.onload = function() {
    window.webkit.messageHandlers.callbackHandler.postMessage(
        JSON.stringify({body: "window finished loading"}));
};

問題是如何將該行通知附加到現有的window.onload並定義一個不存在的window.onload 其他想法也歡迎,例如,排隊window.load實現?

為了完整WKWebView我在下面包括了兩種已知的方法來本地使用WKWebView獲取此類通知。

(1)獲取WKNavigationDelegate生命周期通知,但是當網頁尚未完全呈現時,回調通知觸發得太早。

class ViewController: UIViewController {
    // ...
    func webView(webView: WKWebView, didFinishNavigation navigation: WKNavigation!) {
        NSLog("didFinishNavigation callback received ... too early!")
    }
}

(2)使用鍵值觀察者方法(KVO),但在這里回調通知再次觸發也為時過早:

webView.addObserver(viewController, forKeyPath: "estimatedProgress", options: .New, context: nil)
//
override func observeValueForKeyPath(keyPath: String?, ofObject object: AnyObject?, change: [String : AnyObject]?, context: UnsafeMutablePointer<()>) {
    guard let webView = object as? WKWebView else {return}
    guard let change = change else {return}
    guard let keyPath = keyPath else {return}
    switch keyPath {
        case "estimatedProgress":
            if ((1.0 - webView.estimatedProgress) < 1e-10) {
                NSLog("'estimatedProgress' callback received ... too early!")
            }
            break
        default: break
    }
}

對於“加載” KVO,這是相同的問題。

更新:除了已接受的答案外,此其他問題的最高答案running-jquery-after-all-other-js-has- exected也通過輪詢DOM進行特定更改(例如,當所有Javascript具有除了頁面的加載外,還完成了。

除了加載事件,您還可以監聽DOMContentLoaded

您還可以通過執行以下操作在執行堆棧的末尾執行回調:

window.setTimeout(callback, 0);

另外,您可以嘗試在回調中調用removeEventListener

例如:

if (window.addEventListener) {
    var documentIsReady = function() {
        window.removeEventListener("load", documentIsReady);

        if (typeof window.isMyiOSAppAlreadyNotified === 'undefined') {
            window.webkit.messageHandlers.callbackHandler.postMessage(JSON.stringify({body: "window onload"}));
        }
        window.isMyiOSAppAlreadyNotified = true;
    };
    window.addEventListener("load", function() { window.setTimeout(documentIsReady, 0); });
}

為避免使用isMyiOSAppAlreadyNotified變量污染global(window)范圍,您可以應用module模式

我找到了一種可行的方法。 但是,盡管我徒勞地嘗試避免重復通知,但對於某些網頁,我仍然收到兩個通知,但還沒有找到解決它的方法...

if (window.addEventListener) {
    window.addEventListener("load",
        function() {
            // try to make sure it is called only once ...
            if (typeof window.isMyiOSAppAlreadyNotified === 'undefined') {
                // notify my iOS App that the page has finished loading 
                window.webkit.messageHandlers.callbackHandler.postMessage(
                    JSON.stringify({body: "window onload"}));
            }
            window.isMyiOSAppAlreadyNotified = true;
        }
    );
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM