2010-08-29 51 views
65

好吧,所以基本上我想在頁面上有一點JavaScript,以某種方式附加某種全局事件偵聽器,可以檢測並做一些事情,如果發出ajax請求(無需直接從調用),而不管ajax調用如何進行。JavaScript檢測到一個AJAX事件

我想出瞭如何用jQuery來做到這一點 - 如果ajax請求正在完成 jquery。下面是一個這樣的例子代碼:

$.post(
    // requested script 
    'someScript.php', 
    // data to send 
    { 
    'foo' : 'bar', 
    'a' : 'b' 
    }, 
    // receive response 
    function(response){ 
    // do something 
    } 
); // .post 

// global event listener  
$(document).ajaxSend(
    function(event,request,settings){ 
    alert(settings.url); // output: "someScript.php" 
    alert(settings.data); // output: "foo=bar&a=b" 
    } 
); 

有了這個代碼,無論在哪裏/我如何調用$。員額(..),全球事件偵聽器將觸發。如果我使用$ .get或$ .ajax(任何jquery ajax方法),它也可以工作,不管我怎樣/何時調用它(作爲onclick附加,在頁面加載時,不管)。

但是,我希望能夠擴展這個偵聽器來觸發,而不管使用什麼js框架,或者即使沒有使用框架。因此,舉例來說,如果我是網頁上有以下代碼(從W3Schools的通用Ajax代碼):

function loadXMLDoc() 
{ 
if (window.XMLHttpRequest) 
    {// code for IE7+, Firefox, Chrome, Opera, Safari 
    xmlhttp=new XMLHttpRequest(); 
    } 
else 
    {// code for IE6, IE5 
    xmlhttp=new ActiveXObject("Microsoft.XMLHTTP"); 
    } 
xmlhttp.onreadystatechange=function() 
    { 
    if (xmlhttp.readyState==4 && xmlhttp.status==200) 
    { 
    document.getElementById("myDiv").innerHTML=xmlhttp.responseText; 
    } 
    } 
xmlhttp.open("GET","test.txt",true); 
xmlhttp.send(); 
} 

然後,我有一些隨機鏈接一個onclick調用該函數,我全球阿賈克斯事件監聽器應該能夠檢測到這個請求。那麼我將這段代碼添加到我的頁面,並將它附加到隨機鏈接的onclick(是的,代碼本身工作),但上面的jquery「全局事件偵聽器」代碼未能檢測到該調用。

我做了一些更多的挖掘,我知道我基本上可以將對象保存到臨時對象,並用一個「包裝器」對象覆蓋當前對象,該對象將調用指定的函數,然後調用臨時函數,但這需要我提前知道正在創建/使用的原始對象。但我不會總是知道,提前...

所以......這是可能的嗎?是否有某種方法可以檢測出ajax get/post請求,而不管它是用通用對象還是用xyz框架完成的?或者我只是需要重複代碼來處理每個框架,並且還要提前知道正在創建/使用的ajax對象?

編輯:

我忘了提,這是不夠的,檢測發生的請求。我還需要捕獲請求中發送的數據。以下評論中提供的鏈接將有助於弄清楚是否提出了「一個」請求,但不能獲得發送的數據。附: - 下面的鏈接提供的答案不是很清楚,至少對我來說無論如何。

+4

可能重複[搞清楚何時XMLHttpRequest請求沒有回調](http://stackoverflow.com/questions/2255248/figuring-out-when-a-xmlhttprequest-request-was-made-without-callbacks) – 2010-08-29 21:32:25

+0

感謝您的鏈接!這個問題並不完全如此,因爲我需要也能夠捕獲請求中發送的數據(我想我忽略包含它;編輯)。但是,它使我走上了正確的軌道,我想我找到了一個解決方案,將在測試完成後發佈。謝謝! – 2010-08-30 00:30:08

+0

我認爲你正在尋找的是關於操縱原型的問題,但以更好的方式https://stackoverflow.com/q/20689481/3462483 – doz87 2017-07-20 15:11:03

回答

99

好吧,這是我想出迄今:

<script type='text/javascript'> 
var s_ajaxListener = new Object(); 
s_ajaxListener.tempOpen = XMLHttpRequest.prototype.open; 
s_ajaxListener.tempSend = XMLHttpRequest.prototype.send; 
s_ajaxListener.callback = function() { 
    // this.method :the ajax method used 
    // this.url :the url of the requested script (including query string, if any) (urlencoded) 
    // this.data :the data sent, if any ex: foo=bar&a=b (urlencoded) 
} 

XMLHttpRequest.prototype.open = function(a,b) { 
    if (!a) var a=''; 
    if (!b) var b=''; 
    s_ajaxListener.tempOpen.apply(this, arguments); 
    s_ajaxListener.method = a; 
    s_ajaxListener.url = b; 
    if (a.toLowerCase() == 'get') { 
    s_ajaxListener.data = b.split('?'); 
    s_ajaxListener.data = s_ajaxListener.data[1]; 
    } 
} 

XMLHttpRequest.prototype.send = function(a,b) { 
    if (!a) var a=''; 
    if (!b) var b=''; 
    s_ajaxListener.tempSend.apply(this, arguments); 
    if(s_ajaxListener.method.toLowerCase() == 'post')s_ajaxListener.data = a; 
    s_ajaxListener.callback(); 
} 
</script> 

方向:

就C/P此到您的網頁或將其包含在.js文件或什麼的。這將創建一個名爲s_ajaxListener的對象。每當一個AJAX GET或POST請求時,s_ajaxListener.callback()被調用,並且以下屬性:

s_ajaxListener.method:使用的AJAX方法。這應該是GET或POST。注意:該值可能不總是大寫,它取決於特定請求的編碼方式。我正在爭論自動上層的智慧,或者將它留給別的toLowerCase()來進行不區分大小寫的比較。

s_ajaxListener.url:請求的腳本的URL(包括查詢字符串,如果有的話)(urlencoded)。我注意到,根據數據的發送方式和瀏覽器/框架的不同,例如這個值最終可能是「」或「+」或「%20」。我正在辯論解碼它在這裏的智慧或將它留給別的東西。

s_ajaxListener.data:數據發送時,如有的話例如:富=酒吧& A = B(同 '問題' 作爲同在一處網址編碼.URL)

NOTES:

現在,這不是IE6兼容。這個解決方案對我來說不夠好,因爲我希望它與IE6兼容。但是因爲很多其他人不關心IE6,所以我決定將我的解決方案發布到當前狀態,因爲如果你不關心IE6,它應該適合你。

我已經在(截至此發佈日期)測試過此效果:當前Safari,當前Chrome,當前FireFox,IE8,IE8(IE7兼容)。它目前不支持IE6,因爲IE6使用ActiveX對象,而幾乎所有的東西都使用XMLHttpRequest。

現在我沒有任何線索如何,以及基本原型/擴展/重載(?)ActiveXObject(「Microsoft.XMLHTTP」)。這正是我目前正在研究的...有人知道嗎?

在我上面測試過的每一個瀏覽器下,這都適用於來自通用對象的AJAX請求,以及來自jquery和原型框架的AJAX請求。我知道那裏有其他的框架,但IMO這兩個主要的框架。我可能可能是QA MooTools,但除此之外,我只用測試這些就可以。

如果有人想通過其他瀏覽器和/或框架的測試和發佈結果作出貢獻,我們將不勝感激:)

+1

你可以爲IE6定義一個包裝函數,比如[Sarissa](http ://dev.abiss.gr/sarissa/)確實;看看[重新發明XMLHttpRequest](http://www.ilinsky.com/articles/XMLHttpRequest/),看看如何做到這一點(我現在沒有時間了)。你[不能擴展]一個ActiveX對象,但是你不可以擴展(http://stackoverflow.com/questions/594428/how-can-i-add-properties-to-an-object-in-ie6/594460#594460)可以擴展你自己的包裝函數,只需模擬所需的屬性。我認爲大多數庫測試'window.XMLHttpRequest'的存在,你的包裝器對象將被檢測到。 – 2010-08-30 15:24:39

+0

還要注意IE8在IE7兼容模式下≠IE7。我懷疑'XMLHttpRequest'對象是不同的東西之一:在IE7中它似乎只是一個ActiveX組件的包裝函數,而在IE8中它可能被實現爲'真正'的XHR對象。 – 2010-08-30 16:14:16

+1

目前在FireFox中無法使用。 XMLHttpRequest.open.apply出錯 – HMR 2014-11-15 16:14:26

5

對於IE 6兼容性,怎麼樣:的

<script type='text/javascript'> 
    var s_ajaxListener = new Object(); 

    // Added for IE support 
    if (typeof XMLHttpRequest === "undefined") { 
    XMLHttpRequest = function() { 
     try { return new ActiveXObject("Msxml2.XMLHTTP.6.0"); } 
     catch (e) {} 
     try { return new ActiveXObject("Msxml2.XMLHTTP.3.0"); } 
     catch (e) {} 
     try { return new ActiveXObject("Microsoft.XMLHTTP"); } 
     catch (e) {} 
     throw new Error("This browser does not support XMLHttpRequest."); 
    }; 
    } 

    s_ajaxListener.tempOpen = XMLHttpRequest.prototype.open; 
    s_ajaxListener.tempSend = XMLHttpRequest.prototype.send; 
    s_ajaxListener.callback = function() { 
    // this.method :the ajax method used 
    // this.url :the url of the requested script (including query string, if any) (urlencoded) 
    // this.data :the data sent, if any ex: foo=bar&a=b (urlencoded) 
    } 

    XMLHttpRequest.prototype.open = function(a,b) { 
    if (!a) var a=''; 
    if (!b) var b=''; 
    s_ajaxListener.tempOpen.apply(this, arguments); 
    s_ajaxListener.method = a; 
    s_ajaxListener.url = b; 
    if (a.toLowerCase() == 'get') { 
     s_ajaxListener.data = b.split('?'); 
     s_ajaxListener.data = s_ajaxListener.data[1]; 
    } 
    } 

    XMLHttpRequest.prototype.send = function(a,b) { 
    if (!a) var a=''; 
    if (!b) var b=''; 
    s_ajaxListener.tempSend.apply(this, arguments); 
    if(s_ajaxListener.method.toLowerCase() == 'post')s_ajaxListener.data = a; 
    s_ajaxListener.callback(); 
    } 
</script> 
+5

是的,這是我在當時所做的幾乎..但IE6是沒有人應該支持了,特別是自從微軟自己停止支持它(通過延長不支持XP)截至2014年4月 – 2014-05-14 15:12:39