亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 開發 > AJAX > 正文

如何掌握AJAX之AJAX通訊技術

2024-09-01 08:26:26
字體:
來源:轉載
供稿:網友
當在網上沖浪時,將在瀏覽器和服務器之間存在大量的請求。最初,所有的這種請求都是在用戶做出需要這一步驟的明顯操作時發生的。Ajax技術將開發人員從等待用戶做出這樣的操作中解放出來,允許他在任何時間創建一個對服務器的調用。
Ajax通信支持許多不同的技術。每一種技術都有自己的優點和缺點,因此了解什么情況使用哪一種技術是很重要的。

  隱藏幀技術

  隨著HTML幀的引入,隱藏幀(hidden frame)技術也應運而生了。該技術后面的基本想法是創建一個幀集,其中包含用于客戶端—服務器通信的隱藏幀??梢酝ㄟ^將幀的寬度或高度設置為0像素來隱藏一個幀,以使其不顯示。盡管一些早期的瀏覽器(諸如Netscape 4)不能夠完全隱藏幀,經常會留下一些明顯的幀邊框,但該技術還是廣泛地為開發人員所采用。

  1. 模式

  隱藏幀技術遵循一種特定的四步模式(參見圖2-1)。第一步總是從一個與用戶交互的Web頁面中的可見幀開始的。顯然,用戶并不知道隱藏幀的存在(在現代瀏覽器中,它是不顯示的),以通常的形式與網頁進行交互。在某些時間,用戶執行了一個需要從服務器獲取額外數據的操作。當這個操作發生時,第一步就發生了:產生一個對隱藏幀的JavaScript函數調用。這個調用可以簡單地將隱藏幀重定向到另一個頁面,或者復雜地傳送表單數據。不管這個函數有多復雜,其結果都是產生第2步:向服務器發送一個請求。

圖 2-1

  該模式中的第3步是從服務器上接收一個響應。由于處理的是幀,因此該響應必然是另一個網頁。該網頁必須包含從服務器返回的所請求的數據,同時一些JavaScript將把這些數據傳給可見的幀。通常,這是通過在返回的網頁中分配一個onload事件處理函數(event handler)做到的,該網頁在其全部載入之后調用可見幀中的函數(這就是第4步)。當數據位于可見幀中后,該幀就可以決定如何處理這些數據了。

  2. 隱藏幀的GET請求

  我們已經闡述了隱藏幀技術的基本原理,現在將更深入地研究它。對于任何一種新技術,最好的方法就是通過具體的實例來學習。在該實例中,將創建一個簡單的查詢頁面,客戶服務代表通過該頁面可以查詢客戶的信息。由于這是本書的第一個例子,因此它十分的簡單:用戶輸入客戶ID,然后接收與該客戶相關的信息。由于該功能通常需要數據庫支持,因此還必須做一些服務器端的開發。該例子使用的是PHP——這是一種優秀的開源服務端語言,還將使用到MySQL(在從www.mysql.org下載)——這是一種與PHP結合得很好的開源數據庫。盡管本例確定為使用MySQL,但只需少量的修改就可以在其他數據庫上運行。

  首先,在實現客戶資料查詢之前,你必須有一個包含該信息的數據庫表??梢允褂靡韵耂QL腳本來創建一個客戶表:


CREATE TABLE `Customers` (
 `CustomerId` int(11) NOT NULL auto_increment,
 `Name` varchar(255) NOT NULL default '',
 `Address` varchar(255) NOT NULL default '',
 `City` varchar(255) NOT NULL default '',
 `State` varchar(255) NOT NULL default '',
 `Zip` varchar(255) NOT NULL default '',
 `Phone` varchar(255) NOT NULL default '',
 `E-mail` varchar(255) NOT NULL default '',
 PRIMARY KEY (`CustomerId`)
) TYPE=MyISAM COMMENT='Sample Customer Data';

 


  在這張數據庫表中最重要的字段是CustomerId,我們將通過它來查詢客戶信息。你可以在www.wrox.com下載這個腳本以及一些測試數據。當建好數據庫表后,就可以將精力轉到HTML代碼上了。要使用隱藏幀技術,首先必須創建一個HTML幀集,例如:

 

 

<frameset rows="100%,0" frameborder="0">
?。糵rame name="displayFrame" src="display.htm" noresize="noresize" />
?。糵rame name="hiddenFrame" src="about:blank" noresize="noresize" />
</frameset>

 


  這部分代碼中最重要的是<frameset/>元素的rows屬性。通過將其設置為100%,0,瀏覽器就知道不顯示名為hiddenFrame的第二個幀了。緊接著,將frameborder屬性設置為0則是確保每個幀都沒有可見的邊框。在幀集聲明中最后一個重要的步驟是為每個幀設置noresize屬性,使得用戶不可能在不經意間調整幀的大小而發現隱藏幀,隱藏幀的內容永遠不會成為可顯示的用戶界面的一部分。接下來要處理的是一個請求和顯示客戶信息的頁面。這是一個相對簡單的頁面,由一個用來輸入客戶ID的文本框,一個執行請求的按鈕,以及用來顯示查詢到的客戶信息的<div>元素所組成:

 

 

<p>Enter customer ID number to retrieve information:</p>
<p>Customer ID: <input type="text" id="txtCustomerId" value="" /></p>
<p><input type="button" value="Get Customer Info"
onclick="requestCustomerInfo()" /></p>
<div id="divCustomerInfo"></div>

 


  注意,按鈕調用的是名為requestCustomerInfo()的函數,該函數將負責與隱藏幀交互以獲取數據。它將獲取文本框中的值,將其添加到getcustomerdata.php的查詢字符串上,以getcustomerdata.php?id=23的格式創建一個URL。然后將這個URL指派給隱藏幀,以下就是這個函數的代碼:

 

 

function requestCustomerInfo() {
 var sId = document.getElementById("txtCustomerId").value;
 top.frames["hiddenFrame"].location = "getcustomerdata.php?id=" + sId;
}

 


  該函數的第一步是從文本框中獲取客戶標識號("txtCustomerId")。這是將文本框的ID txtCustomerId作為參數,調用document.getElementById()函數,并獲取返回的value屬性(value屬性保存了文本框中的文本內容)來實現的。然后,將這個ID添加到字符串getcustomerdata.php?id=之后生成完整的URL。第二行代碼則是創建此URL并將其賦給隱藏幀。為了獲得對隱藏幀的引用,首先要使用top對象來獲取瀏覽器的頂級窗口(topmost window)。該對象擁有一個frames數組,在其中可以找到這個隱藏幀。由于每個幀都是一個窗口對象,因此可以將其位置設置為預期的URL。

  這是發出請求所需的所有信息。注意,由于這是一個GET請求(通過一個查詢字符串傳遞信息),因此是很簡單的。(很快,你將看到如何使用隱藏幀技術來執行一個POST請求。)除了requestCustomerInfo()函數之外,還需要另一個在查詢后顯示客戶信息的函數。當數據返回時,隱藏幀將調用這個displayCustomerInfo()函數,其唯一的參數是包含要顯示的客戶數據的字符串:

 

 

function displayCustomerInfo(sText) {
 var divCustomerInfo = document.getElementById("divCustomerInfo");
 divCustomerInfo.innerHTML = sText;
}

 


  在這個函數中,第一行代碼將查詢對用于數據顯示的<div/>元素的引用。第二行代碼將把包含客戶信息的字符串(sText)的值賦給<div/>元素的innerHTML屬性。使用innerHTML屬性,可以將HTML嵌入到格式化的字符串中。這將由主顯示頁面的代碼來完成?,F在我們將創建服務器端程序邏輯。getcustomerdata.php中的基本代碼是在基本的HTML頁面上添加兩處PHP代碼:

 

 

<html>
<head>
<title>Get Customer Data</title>
<?php
//php代碼
?>
</head>
<body>
<div id="divInfoToReturn"><?php echo sInfo ?></div>
</body>
</html>

 


  在該頁面中,第一個PHP代碼塊將包括查詢客戶數據的邏輯(很快將討論到)。而第二個PHP代碼塊則負責將包含客戶數據的sInfo變量的值輸出到<div/>元素中。從這個<div/>元素中,你可以讀取該數據并將數據傳送給顯示幀。為此,需要創建在頁面完全載入后調用的JavaScript函數。

 

 

window.onload = function () {
 var divInfoToReturn = document.getElementById("divInfoToReturn");
top.frames["displayFrame"].displayCustomerInfo(divInfoToReturn.innerHTML);
};

 


  該函數將直接賦給window.onload事件處理函數中。它首先獲取對包含客戶信息的<div/>元素的引用,然后使用數組top.frames訪問顯示幀,并調用前面定義的display CustomerInfo()函數,將其傳給<div/>元素的innerHTML屬性。這就是所有與發送該信息相關的JavaScript。但首先如何獲取這些信息呢?需要一些PHP代碼來從數據庫查詢信息。在PHP代碼中的第一步是定義所有需要的數據塊。在本例中,這些數據塊包括用來查詢的客戶ID、返回信息的sInfo變量,以及訪問數據庫所需要的信息(數據庫服務器、數據庫名、用戶名、密碼以及SQL查詢字符串):

 

 

<?php
 sID = _GET["id"];
 sInfo = "";
 sDBServer = "your.databaser.server";
 sDBName = "your_db_name";
 sDBUsername = "your_db_username";
 sDBPassword = "your_db_password";
 sQuery = "Select * from Customers where CustomerId=".sID;

 //更多代碼
?>

 


  這段代碼首先從查詢字符串中獲取id參數。為了便于獲取,PHP將所有的查詢字符串參數組織于-GET數組中。這個id存儲在sID中,它將用來創建存儲于sQuery中的SQL查詢字符串。在此還將創建sInfo變量,并將其設置為空字符串。在這段代碼中的所有其他變量,都包含了指定特定數據庫配置的信息,根據你自己的實現環境將其替換為正確的值。獲取了用戶的輸入,做好了連接數據庫的基本準備,下一步就是創建數據庫連接,執行查詢,返回結果。如果存在一個指定ID的客戶,sInfo將填入包含所有數據的HTML字符串,包括對電子郵件地址創建一個鏈接,如果客戶ID是無效的,那么sInfo將填入錯誤消息,以傳給顯示幀:

 

 

<?php
 sID = _GET["id"];
 sInfo = "";
 sDBServer = "your.databaser.server";
 sDBName = "your_db_name";
 sDBUsername = "your_db_username";
 sDBPassword = "your_db_password";
 sQuery = "Select * from Customers where CustomerId=".sID;
 oLink = mysql_connect(sDBServer,sDBUsername,sDBPassword);
 @mysql_select_db(sDBName) or sInfo="Unable to open database";

 if(oResult = mysql_query(sQuery) and mysql_num_rows(oResult) > 0) {
  aValues = mysql_fetch_array(oResult,MYSQL_ASSOC);
  sInfo = aValues['Name']."<br />".aValues['Address']."<br />".
aValues['City']."<br />".aValues['State']."<br />".
aValues['Zip']."<br /><br />Phone: ".aValues['Phone']."<br />".
"<a href=/"mailt".aValues['E-mail']."/">".
aValues['E-mail']."</a>";
 } else {
  sInfo = "Customer with ID sID doesn't exist.";
 }
 mysql_close(oLink);
?>

 


  突出顯示的頭兩行代碼用來完成從PHP到MySQL數據庫的連接。緊接著,調用mysql_ query()函數來執行SQL查詢。如果函數返回結果,并且該結果至少包括一行,那么程序將獲取該信息,并將其存入變量sInfo中;否則,sInfo將填入一個錯誤消息。最后兩行則負責釋放數據庫連接。

  關于更復雜的PHP和MySQL編程的闡述已超出了本文討論的范圍。現在當sInfo輸出到<div/>元素時,它將包含正確的信息。onload事件處理函數將讀取這些數據,然后將其發送到顯示幀上。如果查詢到客戶,其相應的信息將會顯示出來,如圖2-2所示。另一方面,如果客戶不存在,則會在屏幕的相同位置顯示錯誤消息。無論如何,客戶服務代表都將獲得一個很好的用戶體驗。你的第一個Ajax程序也就完成了。


圖 2-2

  3. 隱藏幀的POST請求

  前面的例子使用GET請求來從數據庫中獲取信息。由于客戶ID能夠以查詢字符串的形式添加到URL中,因此十分簡單。但如果需要發送POST請求該怎么辦呢?它也可以使用隱藏幀技術,不過需要一些額外的工作。POST請求通常是用于向服務器發送數據的場合,而與GET請求僅從服務器上獲取數據不同。盡管GET請求可以通過查詢字符串來向服務器發送額外的數據,但一些瀏覽器最多只能夠處理512KB以內的查詢字符串信息。對于POST請求而言,則可以發送2GB的信息,能夠良好地滿足絕大多數的應用。

  從傳統意義上說,只能夠通過將表單的method屬性設置為post來發送POST請求。然后,包含在表單中的數據就會通過POST請求發送到action屬性中指定的URL上。更復雜的問題是當表單提交之后,將會從當前頁跳轉到一個新的URL上,這與Ajax的目的是背道而馳的。但萬幸的是,可以通過表單中一個不太知名的target屬性來簡單實現。<form/>元素的target屬性的功能從某種意義上說與<a/>元素的target屬性的功能類似:用來指定跳轉的目的URL。通過設置表單元素的target屬性,可以有效地使得在其他幀或窗口(在本例中是隱藏幀)中顯示出表單的提交結果之后,表單頁面仍然保持不變。首先重新定義一個幀集。與上一個例子唯一不同的是可見幀包含了用來輸入客戶數據的表單:

 

 

<frameset rows="100%,0" frameborder="0">
?。糵rame name="displayFrame" src="entry.htm" noresize="noresize" />
 <frame name="hiddenFrame" src="about:blank" noresize="noresize" />
</frameset>

 


  輸入表單的內容包含在一個<form/>元素中,而且針對保存在數據庫中的每個字段都有一個相應的文本框(除了自動生成的客戶ID之外)。同樣也有一個<div/>元素,用來顯示與客戶端—服務器通信相關的狀態信息:

 

 

<form method="post" action="SaveCustomer.php" target="hiddenFrame">
<p>Enter customer information to be saved:</p>
<p>Customer Name: <input type="text" name="txtName" value="" /><br />
Address: <input type="text" name="txtAddress" value="" /><br />
City: <input type="text" name="txtCity" value="" /><br />
State: <input type="text" name="txtState" value="" /><br />
Zip Code: <input type="text" name="txtZipCode" value="" /><br />
Phone: <input type="text" name="txtPhone" value="" /><br />
E-mail: <input type="text" name="txtEmail" value="" /></p>
<p><input type="submit" value="Save Customer Info" /></p>
</form>
<div id="divStatus"></div>

 


  注意,<form/>元素的target屬性也設置為hiddenFrame,因此當用戶點擊該按鈕時,提交的結果將顯示在隱藏幀中。在本例中,主頁面中只需要一個JavaScript函數:savaResult()。當隱藏幀返回客戶數據保存結果時,將調用該函數:

 

 

function saveResult(sMessage) {
 var divStatus = document.getElementById("divStatus");
 divStatus.innerHTML = "Request completed: " + sMessage;
}

 


  隱藏幀的職責是向該函數傳遞一個消息,該消息將顯示給用戶。它可能是信息已保存的確認信息,或者是說明為什么保存失敗的錯誤信息。接下來處理POST請求的文件是SavaCustomer.php。與前一個例子一樣,該頁面也是由簡單的HTML頁面加上一些PHP和JavaScript代碼組成的。其中PHP代碼用來從請求中收集信息,然后將其保存到數據庫中。由于這是一個POST請求,因此_POST數組中包含了提交的所有信息:

 

 

<?php
 sName = _POST["txtName"];
 sAddress = _POST["txtAddress"];
 sCity = _POST["txtCity"];
 sState = _POST["txtState"];
 sZipCode = _POST["txtZipCode"];
 sPhone = _POST["txtPhone"];
 sEmail = _POST["txtEmail"];
 sStatus = "";

 sDBServer = "your.database.server";
 sDBName = "your_db_name";
 sDBUsername = "your_db_username";
 sDBPassword = "your_db_password";

 sSQL = "Insert into Customers(Name,Address,City,State,Zip,Phone,`E-mail`) ".
" values ('sName','sAddress','sCity','sState', 'sZipCode'".
", 'sPhone', 'sEmail')";

 //更多代碼
?>

 


  這個代碼片段將獲取與客戶相關的所有POST信息;此外,還定義了一個狀態消息(sStatus)以及所需的數據庫信息(與上一個例子相同)。這里的SQL語句是一個INSERT語句,它將獲取的信息添加到數據庫中。
執行這個SQL語句的代碼與上一個例子十分類似:

 

 

<?php
 sName = _POST["txtName"];
 sAddress = _POST["txtAddress"];
 sCity = _POST["txtCity"];
 sState = _POST["txtState"];
 sZipCode = _POST["txtZipCode"];
 sPhone = _POST["txtPhone"];
 sEmail = _POST["txtEmail"];

 sStatus = "";
 sDBServer = "your.database.server";

 sDBName = "your_db_name";
 sDBUsername = "your_db_username";
 sDBPassword = "your_db_password";

 sSQL = "Insert into Customers(Name,Address,City,State,Zip,Phone,`E-mail`) ".
" values ('sName','sAddress','sCity','sState', 'sZipCode'".
", 'sPhone', 'sEmail')";

 oLink = mysql_connect(sDBServer,sDBUsername,sDBPassword);
 @mysql_select_db(sDBName) or sStatus = "Unable to open database";

 if(oResult = mysql_query(sSQL)) {
  sStatus = "Added customer; customer ID is ".mysql_insert_id();
 } else {
  sStatus = "An error occurred while inserting; customer not saved.";
 }

 mysql_close(oLink);
?>

 


  在此,mysql_query()函數的結果只是一個表示語句執行成功的指示器。如果執行成功, sStatus變量中將填入一個消息,表明保存已經成功,并返回為該數據指定的客戶ID。mysql_ insert_id()函數始終返回在最新的INSERT語句返回值的基礎上自動遞增的值。如果因為某些原因,該語句沒有成功執行,sStatus變量將填入一個錯誤消息。sStatus變量將輸出到一個在載入窗口時運行的JavaScript函數中:

 

 

<script type="text/javascript">
 window.onload = function () {
  top.frames["displayFrame"].saveResult("<?php echo sStatus ?>");
 }
</script>

 


  這段代碼調用了savaResult()函數,該函數定義于顯示幀中,傳入的參數值是PHP變量sStatus。由于該變量包含一個字符串,因此必須將PHP的echo語句放在引號中。當執行該函數時,假設客戶數據已保存,則輸入表單頁面看起來如圖2-3所示。


圖 2-3

  當執行這段代碼之后,你還可以自由地使用同樣的表單向數據庫中添加更多客戶,因為它不再消失。

  4. 隱藏iFrame

  新一代的客戶端—服務器通信模式幕后所采用的是iframe,它是在HTML 4.0中引入的。iframe與幀基本是相同的,唯一的區別是iframe可以放在一個未設置幀集的HTML頁面中,可以使頁面中的任意部分成為一個幀。iframe技術可以在未預先設置幀集的頁面中使用,能夠更好地適應于功能的逐漸添加。iframe甚至還可以使用JavaScript在運行時創建,為了簡單起見,語義化HTML(semantic HTML)支持使瀏覽器將Ajax功能看作是一個有益的增強(這將在稍后討論)。由于可以用與普通幀相同的方法使用和訪問iframe,因此它們都是Ajax通信的理想選擇。發揮iframe的優勢有兩種方法。最簡單的方法是在頁面中簡單地嵌入iframe,并像隱藏幀那樣用來發出請求。為此,第一個例子中的顯示頁面將修改為:

 

<p>Enter customer ID number to retrieve information:</p>
<p>Customer ID: <input type="text" id="txtCustomerId" value="" /></p>
<p><input type="button" value="Get Customer Info"
onclick="requestCustomerInfo()" /></p>
<div id="divCustomerInfo"></div>
<iframe src="about:blank" name="hiddenFrame" width="0" height="0"
frameborder="0"></iframe>

  注意,這個iframe中的width、height和frameborder屬性都設置成了0,這可將其從視線中隱去。由于iframe的名字仍是hiddenFrame,所以這個頁面的JavaScript代碼可以如前一樣正常工作。不過,對于GetCustomerData.php頁面還需要做一些小的修改。在該頁面中的JavaScript函數先前是在名為displayFrame的幀中查找displayCustomerInfo()函數。如果你使用該技術,又不存在該名字的幀,則必須修改代碼,用parent來代替它:

window.onload = function () {
 var divInfoToReturn = document.getElementById("divInfoToReturn");
 parent.displayCustomerInfo(divInfoToReturn.innerHTML);
};

  現在這個例子能夠和本文中的第一例子一樣正常工作了。

  第二種使用隱藏iframe的方法是通過JavaScript動態地創建它們。由于并非所有瀏覽器實現iframe的方法都是一樣的,所以需要一些技巧,使得它有助于一步步地創建隱藏的iframe。

  第一步很簡單,使用document.createElement()方法創建iframe并賦予必要的屬性:

function createIFrame() {
 var oIFrameElement = document.createElement("iframe");
 oIFrameElement.width=0;
 oIFrameElement.height=0;
 oIFrameElement.frameBorder=0;
 oIFrameElement.name = "hiddenFrame";
 oIFrameElement.id = "hiddenFrame";
 document.body.appendChild(oIFrameElement);

 //更多代碼
}

  本段代碼的最后一行很重要,因為它將iframe添加到document結構中;沒有添加到document中的iframe是無法執行請求的。另外注意,該iframe的name和id屬性都是設置為hiddenFrame。這是必要的,因為有些瀏覽器是通過name屬性訪問新的幀,而有些則是通過id屬性新的幀。緊接著定義一個全局變量,用來保存對該幀對象的引用。注意,針對iframe元素的這個幀對象并非是從createElement()函數返回的。要獲得該對象,必須從幀集合中獲取。以下就是即將保存在全局變量中的內容:

var oIFrame = null;

function createIFrame() {
 var oIFrameElement = document.createElement("iframe");
 oIFrameElement.width=0;
 oIFrameElement.height=0;
 oIFrameElement.frameBorder=0;
 oIFrameElement.name = "hiddenFrame";
 oIFrameElement.id = "hiddenFrame";
 document.body.appendChild(oIFrameElement);

 oIFrame = frames["hiddenFrame"];
}

  如果你將這些代碼放到前面的iframe例子中,那么需要對requestCustomerInfo()函數進行如下修改:

function requestCustomerInfo() {
 if (!oIFrame) {
  createIFrame();
  setTimeout(requestCustomerInfo, 10);
  return;
 }

 var sId = document.getElementById("txtCustomerId").value;
 oIFrame.location = "GetCustomerData.php?id=" + sId;
}

  基于這些修改,該函數將會檢查oIFrame是否為空。如果為空,則調用createFrame(),并會為該函數的調用設置10ms的超時時間。這是很必要的,因為只有IE瀏覽器能夠立即識別插入的iframe,大部分其他瀏覽器需要花幾毫秒來識別它,以允許通過它發送請求。當再次執行該函數時,將執行代碼的其余部分,其中最后一行已經修改為對OIFrame對象的引用。盡管該技術能夠很容易地應用于GET請求,但POST請求卻完全不同。只有一部分瀏覽器允許你設置表單的target屬性來動態創建iframe;但IE并不是其中的一種。因此,要使用隱藏iframe技術來發送POST請求還需要一些技巧。

 

  5. 隱藏iframe的POST請求

  要使用隱藏iframe來完成POST請求,其方法是在隱藏幀中載入一個包含表單的頁面,用數據填充該表單,然后再提交該表單。當這個可見的表單(你實際輸入數據的那個)提交時,必須取消這次提交而將信息轉發給隱藏幀。為此,必須定義一個函數,用來處理iframe的創建以及隱藏表單的載入:

 

function checkIFrame() {
 if (!oIFrame) {
  createIFrame();
 }
 setTimeout(function () {
  oIFrame.location = "ProxyForm.htm";
 }, 10);
}

  這個名為checkIFrame()的函數首先檢查隱藏的iframe是否已經創建。如果沒有,則調用createIFrame()。然后,在將iframe的地址設置為ProxyForm.htm(這是一個隱藏表單頁面)之前,為其設置一個超時值。由于該函數調用需要花一些時間,而重要的是該頁面每次加載時都將提交該表單。ProxyForm.htm文件很簡單,只包括很少的JavaScript,用來提示主頁面已經裝載完成:

<html>
<head>
<title>Proxy Form</title>
<script type="text/javascript">
 window.onload = function () {
  parent.formReady();
 }
</script>
</head>
<body>
<form method="post"></form>
</body>
</html>

  正如你所見,該頁面的主體只包含一個空的表單,而標題中只包含一個onload事件處理函數。當載入該頁面時,頁面將通過調用parent.formReady()來使主頁面知道它已經做好接收請求的準備。而formReady()函數則是包含在主頁面本身中的,類似于:

function formReady() {
 var oHiddenForm = oIFrame.document.forms[0];
 var oForm = document.forms[0];

 for (var i=0 ; i < oForm.elements.length; i++) {
  var oHidden = oIFrame.document.createElement("input");
  oHidden.type = "hidden";
  oHidden.name = oForm.elements[i].name;
  oHidden.value = oForm.elements[i].value;
  oHiddenForm.appendChild(oHidden);
 }
 oHiddenForm.action = oForm.action;
 oHiddenForm.submit();
};


  在該函數中的第一步是獲取對隱藏iframe中表單的引用,可以通過訪問該幀的document.forms集合來獲取。由于在該頁面中只有一個表單,因此可以安全地從該集合中獲得第一個表單(即索引值為0),并將其存儲于oHiddenForm中。然后,將對主頁面表單的引用存于oForm中。緊接著,一個for循環對主頁面中該表單的各元素進行遍歷(使用elements集合)。對于表單中的每一個元素,都將在隱藏幀(注意,必須使用oIFrame.document.createElement()而不只是document.createElement())中創建一個隱藏的輸入元素。這個隱藏的輸入元素擁有與該表單元素相同的名字和值,然后使用appendChild()函數將其添加到隱藏的表單中。

  當所有的表單元素都添加完后,隱藏的表單還將設置與主頁面表單相同的action。通過從表單中讀取action來取代硬編碼,就可以在任何頁面中使用formReady()。該函數的最后一步是提交這個隱藏的表單。剩下的最后一件事就是確保主頁面的表單不以通常的方式提交自己。要達到這一目標,只需在onsubmit事件處理函數中調用checkIFrame()并返回false:

<form method="post" action="SaveCustomer.php"
onsubmit="checkIFrame();return false">

<p>Enter customer information to be saved:</p>
<p>Customer Name: <input type="text" name="txtName" value="" /><br />
Address: <input type="text" name="txtAddress" value="" /><br />
City: <input type="text" name="txtCity" value="" /><br />
State: <input type="text" name="txtState" value="" /><br />
Zip Code: <input type="text" name="txtZipCode" value="" /><br />
Phone: <input type="text" name="txtPhone" value="" /><br />
E-mail: <input type="text" name="txtEmail" value="" /></p>
<p><input type="submit" value="Save Customer Info" /></p>
</form>
<div id="divStatus"></div>


  通過以這種方式返回flase,可以阻止表單的默認行為(將自己提交到服務器)。通過調用checkIFrame()方法來啟動隱藏iframe中表單的提交進程。當這一任務完成后,就可以像使用隱藏幀POST請求的例子一樣使用本例;頁面SavaCustomer.php負責處理數據,并當完成時調用主頁面中的savaResult()函數。注意,本節中的例子是為了使其聚焦于與Ajax技術相關的問題上,因而進行了簡化。如果在實際的Web應用程序中使用,還需要提供更多的用戶反饋,諸如在發出請求時屏蔽該表單的輸入等。

  6. 隱藏幀技術的優點和缺點

  現在,你已經對使用隱藏幀所實現的強大功能有所了解了,我們將討論它的實用性。正如前面所說的,該技術已經存在多年,并且仍然在許多Ajax應用中使用。使用隱藏幀的一個最大理由之一是它可以維護瀏覽器的歷史,使用戶仍然能夠使用瀏覽器上的后退和前進按鈕。瀏覽器由于并不知道隱藏幀實際上被隱藏了,但對于其所發出的請求仍然是記錄在案的。然而,Ajax應用程序的主頁面卻沒有修改,在隱藏幀中的修改意味著后退和前進按鈕將依據該隱藏幀的訪問歷史而非主頁面而變化。這也是為什么Gmail和Google Maps仍然使用該技術的理由。

  注意,iframe并非一直會存儲瀏覽器的歷史記錄。盡管IE始終會存儲iframe的歷史記錄,但Firefox只對使用HTML定義(也就是不包括使用JavaScript動態創建)的iframe保存歷史記錄。Safari從不為iframe保存歷史記錄,不管它們是如何包含在該頁面中的。隱藏幀技術不利的一面是,對其背后發生的事了解甚少。它完全依賴于返回的正確頁面。本節的例子都存在相同的問題:如果隱藏幀的頁面載入失敗,并不會向用戶提示出錯消息;主頁面將繼續等待直到調用適當的JavaScript函數。必須通過設置一個較長周期(可能是5分鐘)的超時時間,然后如果頁面仍然沒有成功載入則顯示一條消息,以給用戶一個安慰。但這一切都只是一個變通方法,最主要的問題是,對于后臺發生的HTTP請求缺乏充足的信息。幸運的,我們還有其他選擇。

 

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
狠狠久久亚洲欧美专区| 日本一欧美一欧美一亚洲视频| 欧美性jizz18性欧美| 亚洲欧美国产日韩中文字幕| 国产在线观看不卡| 国产精品久久久久久中文字| 欧美日本亚洲视频| 91午夜在线播放| 欧美亚洲视频一区二区| 亚洲国产精品专区久久| 51精品国产黑色丝袜高跟鞋| 亚洲精品一区av在线播放| 国产女人18毛片水18精品| 日韩电视剧免费观看网站| 亚洲亚裔videos黑人hd| 欧美电影在线观看完整版| 国产精品热视频| 亚洲级视频在线观看免费1级| 欧美日韩国产综合视频在线观看中文| 国产一区二区视频在线观看| 国产欧美va欧美va香蕉在| 神马国产精品影院av| 久久99久久99精品免观看粉嫩| 国产精品v片在线观看不卡| 欧美一级成年大片在线观看| 亚洲第一区第二区| 日韩成人性视频| 午夜精品久久久99热福利| 亚洲毛茸茸少妇高潮呻吟| 欧美日韩中文在线| 国产精品va在线| 国产精品第100页| 91禁国产网站| 久久精品国产清自在天天线| 麻豆国产精品va在线观看不卡| 欧美日本亚洲视频| 欧美最猛性xxxxx免费| 亚洲三级av在线| 久久久国产精彩视频美女艺术照福利| 欧美日韩激情视频| 久久综合国产精品台湾中文娱乐网| 久久久久久久久爱| 91精品国产高清久久久久久久久| 日韩在线观看免费全集电视剧网站| 中文.日本.精品| 精品无人国产偷自产在线| 亚洲第一精品夜夜躁人人躁| 国产剧情久久久久久| 欧美色视频日本高清在线观看| 在线电影中文日韩| 亚洲第五色综合网| 亚洲精品wwwww| 国产有码一区二区| 成人中心免费视频| 久久艳片www.17c.com| 中文字幕日韩高清| 91香蕉嫩草神马影院在线观看| 欧美成年人视频| 欧美亚洲国产视频| 亚洲国产高清高潮精品美女| 国产精品丝袜白浆摸在线| 亚洲成人精品视频| 精品在线小视频| 日韩欧美高清视频| 国产盗摄xxxx视频xxx69| 欧美日韩精品国产| 久久久成人精品| 国产精品久久在线观看| 亚洲伊人久久大香线蕉av| 国产精品海角社区在线观看| 亚洲自拍欧美另类| 国产精品精品视频一区二区三区| 欧美高清一级大片| 欧美一二三视频| 精品欧美激情精品一区| 欧美香蕉大胸在线视频观看| 亚洲精品免费一区二区三区| 精品国产精品三级精品av网址| 欧美性猛交xxxx乱大交极品| 欧美性受xxxx黑人猛交| 欧美在线xxx| 国产精品美女www爽爽爽视频| 午夜精品久久久久久久99黑人| 久久久精品中文字幕| 大桥未久av一区二区三区| 国产精品一区二区三区成人| 性金发美女69hd大尺寸| 92版电视剧仙鹤神针在线观看| 日本成熟性欧美| 在线看片第一页欧美| 亚洲综合在线中文字幕| 欧美视频免费在线| 国内精品久久久久久影视8| 一区二区日韩精品| 欧美色欧美亚洲高清在线视频| 欧美一级大片视频| 欧美夜福利tv在线| 国产不卡av在线免费观看| 亚洲伊人久久大香线蕉av| 国产va免费精品高清在线| 亚洲激情在线观看视频免费| 欧美精品亚州精品| 午夜欧美不卡精品aaaaa| 成人免费视频网址| 欧美在线免费观看| 影音先锋欧美精品| 97国产精品人人爽人人做| 日韩女优人人人人射在线视频| 中文.日本.精品| 欧美性生交xxxxx久久久| 国产精品欧美日韩| 久久久久中文字幕| 懂色av影视一区二区三区| 欧美超级乱淫片喷水| 亚洲精品有码在线| 欧美日韩在线视频一区二区| 亚洲精品国精品久久99热一| 欧美色xxxx| 久久久精品国产| 日韩av免费观影| 日韩电影在线观看免费| 成人女保姆的销魂服务| 欧美成人精品在线播放| 欧美日韩在线视频一区二区| 日韩精品免费电影| 中文字幕日韩欧美在线| 久久久久久12| 精品人伦一区二区三区蜜桃网站| 国产不卡精品视男人的天堂| 91在线观看免费网站| 色七七影院综合| 日韩精品视频观看| 色系列之999| 日韩在线观看高清| 亚洲tv在线观看| 日韩视频―中文字幕| 国产精品视频资源| 亚洲午夜精品视频| 国产精品久久久久久亚洲调教| 97久久精品人人澡人人爽缅北| 欧美成人精品在线视频| 亚洲精品电影网站| 亚洲电影免费观看高清| 韩国美女主播一区| 国产精品精品久久久久久| 精品久久久久久中文字幕一区奶水| 伊人亚洲福利一区二区三区| 午夜精品一区二区三区av| 日韩中文字幕网站| 久久97精品久久久久久久不卡| 欧美成人一区二区三区电影| 亚洲一区免费网站| 操人视频在线观看欧美| 庆余年2免费日韩剧观看大牛| 久久深夜福利免费观看| 亚洲国产精品电影| 日韩美女毛茸茸| www.久久久久| 国产91免费看片| 久久久久久久久久国产| 亚洲精品福利资源站| 亚洲黄色成人网| 亚洲成人av片| 欧美成人国产va精品日本一级|