? ? ? ? 最近在項目中有這樣一個需求:在前端頁面的js文件中從后臺獲取一個URL,拿到URL后調用windows.open方法打開這個URL。URL由后端程序拼接而成,在開發過程中遇到了兩個問題,前端js代碼如下:
showWindow : function() {
Fw.Ajax.request({
url : '/ebank/callCenter.do',
params : {'COMPY_NAME':COMPY_NAME},
page : false,
success : function(data) {
callCenterUrl = data.call_center_url;
},
if(callCenterUrl != null) {
window.open(callCenterUrl,'_blank','width=850, height=600, resizable=yes, toolbar=no, menubar=no');
}else {
alert("客服系統繁忙,請稍后再試");
}
onFailure : function() {
},
});
},
1.可能出現先彈出窗口,后拿到URL的情況
- 上面代碼經常出現打開空白頁面的結果,分析原因是Ajax異步請求后端,還沒拿到URL就執行了windows.open方法導致打開了空白頁(URL初始值賦的“_blank”)
- 嘗試解決了一下,將彈窗邏輯放在回調函數success中,確實可以保證先拿到URL后再執行windows.open方法,但是又引出了一個新的問題。
2.瀏覽器攔截彈窗問題
- 將彈窗邏輯放入Ajax的回調函數success中后,彈出窗口在IE瀏覽器遭到攔截:
? ? ? ?其原因是瀏覽器出于安全策略阻擋了非用戶點擊彈出的窗口,所謂非用戶點擊就是彈出的窗口不是直接由用戶點擊事件觸發的彈窗。在這段邏輯當中,彈窗事件由程序發起,所以會被瀏覽器攔截。然而對于用戶來說這種體驗肯定是不好的,你不能指望一個用戶對瀏覽器以及程序了如指掌。于是通過搜索找到一種解決方法,更新后的代碼如下:
showWindow : function() {
//先打開窗口,防止放進Ajax中被瀏覽器攔截
var adPopup = window.open(callCenterUrl,'_blank','width=850, height=600, resizable=yes, toolbar=no, menubar=no');
Fw.Ajax.request({
url : '/ebank/callCenter.do',
params : {'COMPY_NAME':COMPY_NAME},
page : false,
success : function(data) {
callCenterUrl = data.call_center_url;
if(callCenterUrl != null) {
//避免被瀏覽器攔截,重定向窗口
adPopup.location = callCenterUrl;
}else {
alert("客服系統繁忙,請稍后再試");
}
},
onFailure : function() {
},
});
},
- 上述JS代碼將打開窗口動作放在了監聽按鈕點擊事件下,在Ajax函數執行之前,我在項目本地加了一個loading動畫的頁面,在拿到真正后臺傳來的URL之前,彈出的窗口都會在這個Loading頁面等待。一旦Ajax返回了真正的URL,再將窗口重定向到新的URL。經過這種設置,成功解決了彈窗被瀏覽器攔截的問題。
3.對Ajax的好奇與初步探索
- Ajax是什么
AJAX is not a programming language. It is just a technique for creating better and more interactive web applications.
AJAX = Asynchronous JavaScript and XML(異步的 JavaScript 和 XML)。
AJAX 不是新的編程語言,而是一種使用現有標準的新方法。
AJAX 是與服務器交換數據并更新部分網頁的藝術,在不重新加載整個頁面的情況下刷新局部頁面。 - Ajax怎么實現的
- 實際使用了幾次Ajax與后臺進行交互后,我不禁在想,這么好用的技術是怎么實現的?初步猜測是另起了一個線程,在子線程里進行操作,然后在子線程里對局部頁面進行更新。
- 經過搜索,得知Ajax請求的核心是
XMLHttpRequest
,原來整個Ajax與后臺交互與刷新局部頁面的技術是這個對象。對于XMLHttpRequest的介紹有很多,這里僅貼Ajax實現封裝以輔助自己記憶。代碼來自 AJAX的實現原理以及封裝
var $={
/*傳遞參數對象,返回拼接之后的字符串*/
/*{‘name’:’jack,’age’:20}=> name=jack&age=20&*/
getParmeter:function(data){
var result="";
for(var key in data){
result=result+key+"="+data[key]+"&";
}
/*將結果最后多余的&截取掉*/
return result.slice(0,-1);
},
/*實現ajax請求*/
ajax:function(obj){
/*1.判斷有沒有傳遞參數,同時參數是否是一個對象*/
if(obj==null || typeof obj!="object"){
return false;
}
/*2.獲取請求類型,如果沒有傳遞請求方式,那么默認為get*/
var type=obj.type || 'get';
/*3.獲取請求的url location.pathname:就是指當前請求發起的路徑*/
var url=obj.url || location.pathname;
/*4.獲取請求傳遞的參數*/
var data=obj.data || {};
/*4.1獲取拼接之后的參數*/
data=this.getParmeter(data);
/*5.獲取請求傳遞的回調函數*/
var success=obj.success || function(){};
/*6:開始發起異步請求*/
/*6.1:創建異步對象*/
var xhr=new XMLHttpRequest();
/*6.2:設置請求行,判斷請求類型,以此決定是否需要拼接參數到url*/
if(type=='get'){
url=url+"?"+data;
/*重置參數,為post請求簡化處理*/
data=null;
}
xhr.open(type,url);
/*6.2:設置請求頭:判斷請求方式,如果是post則進行設置*/
if(type=="post"){
xhr.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
}
/*6.3:設置請求體,post請求則需要傳遞參數*/
xhr.send(data);
/*7.處理響應*/
xhr.onreadystatechange=function(){
/*8.判斷響應是否成功*/
if(xhr.status==200 && xhr.readyState==4){
/*客戶端可用的響應結果*/
var result=null;
/*9.獲取響應頭Content-Type ---類型是字符串*/
var grc=xhr.getResponseHeader("Content-Type");
/*10.根據Content-Type類型來判斷如何進行解析*/
if(grc.indexOf("json") != -1){
/*轉換為js對象*/
result=JSON.parse(xhr.responseText);
}
else if(grc.indexOf("xml") != -1){
result=xhr.responseXML;
}
else{
result=xhr.responseText;
}
/*11.拿到數據,調用客戶端傳遞過來的回調函數*/
success(result);
}
}
}
};
調用方式與jquery類似的:
$.ajax({
url:'',
type:'',
data: {},
success:function(result){
//code...
}
});
- Ajax出現已經有近20歷史,是否有替代技術?
- 通過我的搜索,發現了一個傳說中將會取代Ajax的技術,叫做Fetch,當然了,具體能不能取代Ajax可能還要繼續觀察,但是對于這技術了解一下總是好的。
- 引用W3C School的一段話:十多年來,XMLHttpRequest 對象一直被 AJAX 操作所接受,但是我們知道,XMLHttpRequest 對象的 API 設計并不是很好,輸入、輸出、狀態都在同一個接口管理,容易寫出非常混亂的代碼。那么Fetch API就應勢而生,提供了一種新規范,用來取代善不完美的 XMLHttpRequest 對象。
Fetch API 主要有兩個特點:一是接口合理化,AJAX 是將所有不同性質的接口都放在 XHR 對象上,而Fetch是將它們分散在幾個不同的對象上,設計更合理;二是Fetch操作返回 Promise 對象,避免了嵌套的回調函數。
接下來將花點時間學習一下Fetch,先附上Fetch API官方文檔。