如果想要在網頁中插入開啟新的瀏覽器視窗的語法,有兩種簡單的作法,一種是直接在連結語法中加入 target=”_blank”,例如 <a href="http://zonble.net/" target="_blank">,另外一種方法則是呼叫 Javascript 的 window.open()
函式。
而雖然這兩者的目的是開啟新的瀏覽器視窗,但是在當你在寫一個使用了 WebKit 的 Cocoa 應用程式的時候,對於這兩個事件,則需要分別給予不同的實作-在 WebView 物件中觸發前者時,WebView 會去呼叫 Policy Delegate 的 webView:decidePolicyForNewWindowAction:request:newFrameName:decisionListener:
這個 Method,但是後者-Javascript 的 window.open()-則會跳過 Policy Delegate,直接向 UI Delegate 呼叫 webView:createWebViewWithRequest:
。
意思就是,在使用者在你的應用程式中的 WebView 中,點選了一個包含 target=”_black” 的連結的時候,WebView 首先會詢問你所指定的 Delegate Object,然後你可以根據狀況判斷,而做出對應的處理-應該開新視窗、開新的瀏覽器分頁(如果你寫的是一套具備分頁功能的瀏覽器應用程式)、或是使用系統預設的瀏覽器開啟。
但是遇到 window.open()
則不然,這個狀況是-事件發生的 WebView 已經決定要因此產生新的 WebView 物件,你需要在 webView:createWebViewWithRequest:
的實作中,回傳一個 WebView 物件,而這個 WebView 物件就會開始載入 window.open()
所傳入的、那個要開啟的 URL。而我們會在這個地方遇到一個問題-基本上我覺得應該算是蘋果的 Bug-在 webView:createWebViewWithRequest:
method 中所傳入的那個 NSURLRequest 物件,居然是 NULL!
假使我們現在要做的事情是,無論遇到哪一種開新視窗的事件,統統都丟到外部瀏覽器開啟。在處理 target=”_blank” 這種狀況時,只要這麼寫,就可以達到想要的效果:
- (void)webView:(WebView *)sender decidePolicyForNewWindowAction:(NSDictionary *)actionInformation request:(NSURLRequest *)request newFrameName:(NSString *)frameName decisionListener:(id < WebPolicyDecisionListener >)listener { NSURL *URL = [request URL]; [[NSWorkspace sharedWorkspace] openURL:URL]; }
然後我們可以試試看,在 webView:createWebViewWithRequest:
中,也採用相同的實作:
- (WebView *)webView:(WebView *)sender createWebViewWithRequest:(NSURLRequest *)request { NSURL *URL = [request URL]; [[NSWorkspace sharedWorkspace] openURL:URL]; return nil; }
完全沒有用。因為 request 物件是 NULL,所以自然沒有辦法取得對應的 URL 物件。查了一下網路上面的討論,看到的說法是-WebView 的確不會傳入 request 物件,因為在遇到 window.open()
要開啟新視窗時,只要靶新的 WebView 準備好,之後就會自動往這個新的 WebView 的 mainFrame 送出 loadRequest:
-既然如此,webView:createWebViewWithRequest:
中設計要傳入 request 物件,這個設計到底是做心酸的還是做好玩的…。而網路上發問的時間是 2004 年,而到了 2009 年這個問題還是始終存在。
後來決定使用醜陋的作法-既然在 code>webView:createWebViewWithRequest: 收不到 request,那麼就回傳一個隱藏的 WebView,而這個 WebView 要開始載入內容的時候,總可以取得 URL 吧?
- (WebView *)webView:(WebView *)sender createWebViewWithRequest:(NSURLRequest *)request { return _hiddenWebView; } - (void)webView:(WebView *)sender didStartProvisionalLoadForFrame:(WebFrame *)frame { if ([sender isEqual:_hiddenWebView]) { NSString *URLString = [sender mainFrameURL]; NSURL *URL = [NSURL URLWithString:URLString]; [[NSWorkspace sharedWorkspace] openURL:URL]; [_hiddenWebView stopLoading:self]; return; } }
為了要在外部開啟網頁,居然要另外準備一個 WebView 物件…。有什麼更好的作法嗎?
能发一个小例子给我参考吗?