1. 程式人生 > >ajax開啟新視窗實現

ajax開啟新視窗實現

最近開發中碰到一個問題,有一場景需要在ajax驗證通過後在新視窗開啟一個url。 一開始通過在非同步回撥函式中使用window.open()來實現,但是發現這種實現方式會被瀏覽器攔截,需要使用者進行瀏覽器設定才能開啟,但是這顯然不 適合在網際網路應用中對使用者做這個限制。因此就想有沒有什麼辦法來解決?

辦法一:失敗

        首先的一個想法是js開啟一個新視窗不行,有可能是瀏覽器對於js直接開啟新視窗有安全限制,那麼我form表單提交或者偽造一個url去觸發click 函式,總不應該會進行攔截了吧。試了之後遺憾地的發現:不行。查了一些資料,瀏覽器只有在認為click和submit在開啟新視窗時(如果是_self 則不會有此限制),這些操作是由使用者主動觸發時才是安全可以被執行,而ajax回撥函式中去執行click和submit被瀏覽器認為不是由使用者主動觸發 的,因此不能被安全執行,所以被攔截。

       程式碼如下:試了之後,無奈的發現,不僅ajax回撥中會被安全攔截,像timeout、interval這種也同樣會被瀏覽器認為不是由使用者主動觸發的操作,而被攔截,無奈失敗了!

 

$.ajax({
    url:url,
    data:form.serialize(),
    dataType: 'json'
}).done(function(o){
    if(o.success){
        if(o.data){
            $('#jump-url-div').val('http://www.XXX.com');
        }else{
                        _onFailure();
                }}else{_onFailure();}
}).fail(_onFailure);
setTimeout(function(){window.open($('#jump-url-div').val());},5000);

 

辦法二:失敗

  然後就想不在ajax非同步回撥中去要開新視窗,而是在ajax執行的函式中去延時去執行開啟新視窗, 想到ajax是非同步呼叫的,那麼我在當前函式裡通過while(true)來判斷url是否獲取完畢,如果取到url就去執行新視窗開啟邏輯,這樣總該可以了吧,於是就寫了程式碼:

 最後一執行,發現瀏覽器被掛住,且一直不開啟新視窗。後來一查才知道,瀏覽器的 javascript執行引擎是單執行緒的,所謂的ajax非同步執行,其實是在成功回撥後,將當前的任務放到瀏覽器的javascript的執行佇列之中, 等待執行。而這裡由於while(true)一直在執行,因此不可能去執行ajax的回撥函式,因此url一直取不到,導致死迴圈,仍然失敗!

 

 

$.ajax({
    url:url,
    data:form.serialize(),
    dataType: 'json'
}).done(function(o){
    if(o.success){
        if(o.data){
            $('#jump-url-div').val('http://www.XXX.com');
        }else{
            _onFailure();
        }
    }else{
        _onFailure();
    }
}).fail(_onFailure);
while(true){
    if($('#jump-url-div').val()!=''){
        window.open($('#jump-url-div').val());
    break;
    }
}

 

 

 

辦法三:成功

後來一想,之所以瀏覽器認為開啟新視窗不是由使用者主動發起的,是因為ajax的非同步請求導致,而ajax不僅可以進行非同步請求,也可以進行同步請求,然後就把這段程式碼的ajax請求改為同步,除錯通過,但是這種方法雖然解決了問題,但是也同樣失去了我們使用ajax的實衷,而且這種方法在jquery的使用手冊裡也明確指出,其受到呼叫的介面的效能影響,如果長時間不響應,勢必會鎖住瀏覽器,失去非同步響應的優勢。

如下:

 

 

$.ajax({
    url:url,
    data:form.serialize(),
    dataType: 'json',
    async:false
}).done(function(o){
    if(o.success){
        if(o.data){
            window.open('http://www.XXX.com');
        }else{
            newwin.close();
            $(document).trigger('simpleDialog',['#dialog-has-order']);
        }
    }else{
        _onFailure();
    }
}).fail(_onFailure);

 

 

 

 辦法四:成功

後來通過進一步查詢,據說淘寶有一種作法,就是在ajax執行之前先開啟一個新視窗,這時候是同步的,所以不會有問題,然後在非同步呼叫成功後使用location.href將其指向新的url,如果失敗則將該視窗關閉,  但是這種方法帶來一個問題,就是當失敗後,會先開啟一個視窗,然後再關閉,雖然一閃而過,但是對使用者總是一個困擾,相對來說還不如將ajax改成同步,畢竟現在的網際網路的訪問速度,不至於會將瀏覽器鎖住太長時間。

如下:

 

 

var newwindow=window.open("about:blank");
window.focus();
$.ajax({
    url:form.attr('action'),
    data:form.serialize(),
    dataType: 'json',
    async:false
}).done(function(o){
    if(o.success){
        if(o.data){
            newwindow.location.href="http://www.XXX.com";
                        newwindow.focus();
        }else{
            newwindow.close();
        }
    }else{
        newwindow.close();
    }
}).fail(function(){newwindow.close();});