[英]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.