深入理解ajax系列第四篇

來源:互聯網
上載者:User

標籤:type   div   inner   mit   檢查   建立   file   title   nbsp   

前面的話

  現代Web應用中頻繁使用的一項功能就是表單資料的序列化,XMLHttpRequest 2級為此定義了FormData類型。FormData為序列化表單以及建立與表單格式相同的資料提供了便利。本文將先介紹表單編碼,然後過渡到表單序列化,最後引出FormData的核心概念

 

表單編碼

  當使用者提交表單時,表單中的資料(每個表單元素的名字和值)編碼到一個字串中並隨請求發送。預設情況下,HTML表單通過POST方法發送給伺服器,而編碼後的表單資料則用做請求主體

  對錶單資料使用的編碼方案相對簡單:對每個表單元素的名字和值執行普通的URL編碼(使用十六進位轉義碼替換特殊字元),使用等號把編碼後的名字和值分開,並使用"&"符號分開名/值對。一個簡單表單的編碼如下所示

find=pizza&zipcode=01234&radius=1km

  表單資料編碼格式有一個正式的MIME類型

application/x-www-form-urlencoded

  當使用POST方法提交這種順序的表單資料時,必須"Content-Type"要求標頭為這個值

  [注意]這種類型的編碼並不需要HTML表單,在Ajax應用中,希望發送給伺服器的很可能是一個javascript對象

  前面展示的資料變成javascript對象的表單編碼形式可能是:

{find: "pizza", zipcode: 01234, radius: "1km"}

  表單編碼在Web上如此廣泛使用,同時所有伺服器端的程式設計語言都能得到良好的支援,所以非表單資料的表單編碼通常也是容易實現的事情

  下面代碼展示了如何?對象屬性的表單編碼

function encodeFormData(data){    if (!data) return "";    //一直返回字串    var pairs = [];            //用於儲存名值對    for(var name in data){         if (!data.hasOwnProperty(name)){            continue;        //跳過繼承屬性        }        if (typeof data[name] === "function"){            continue;         //跳過方法         }        var value = data[name].toString();    //把值轉換成字串        name = encodeURIComponent(name.replace("%20", "+")); //編碼名字        value = encodeURIComponent(value.replace("%20", "+"));//編碼值        pairs.push(name + "=" + value); // 存入名值對     }    return pairs.join(‘&‘); //返回使用‘&‘串連的名值對} 
var data = {name:‘小火柴‘,age:28,sender:‘male‘};//name=%E5%B0%8F%E7%81%AB%E6%9F%B4&age=28&sender=male    console.log(encodeFormData(data));    

 

表單序列化

  隨著Ajax的出現,表單序列化已經成為一種常見需求。在javascript中,可以利用表單欄位的type屬性,連同name和value屬性一起實現對錶單的序列化。在編寫代碼之前,有必須先搞清楚在表單提交期間,瀏覽器是怎樣將資料發送給伺服器的

  1、對錶單欄位的名稱和值進行URL編碼,使用和號(&)分隔

  2、不發送禁用的表單欄位

  3、只發送勾選的複選框和選項按鈕

  4、不發送type為"reset"和"button"的按鈕

  5、多選選擇框中的每個選中的值単獨一個條目

  6、在單擊提交按鈕提交表單的情況下,也會發送提交按鈕;否則,不發送提交按鈕。也包括type為"image"的<input>元素

  7、<select>元素的值,就是選中的<option>元素的value特性的值。如果<option>元素沒有value特性,則是<option>元素的文本值

  在表單序列化過程中,一般不包含任何按鈕欄位,因為結果字串很可能是通過其他方式提交的。除此之外的其他上述規則都應該遵循

  在下面表單序列化serialize()函數中,首先定義了一個名為parts的數組,用於儲存將要建立的字串的各個部分。然後,通過for迴圈迭代每個表單欄位,並將其儲存在field變數中。在獲得了一個欄位的引用之後,使用switch語句檢測其type屬性

  序列化過程中最麻煩的就是<select>元素,它可能是單選框也可能是多選框。為此,需要遍曆控制項中的每一個選項,並在相應選項被選中的情況下向數組中添加一個值。對於單選框,只可能有一個選中項,而多選框則可能有零或多個選中項。這裡的代碼適用於這兩種選擇框,至於可選項的數量則是由瀏覽器控制的。在找到一個選中項之後,需要確定使用什麼值。如果不存在value特性,或者雖然存在該特性,但值為空白字串,都要使用選項的文本來代替。為檢査這個特性,在DOM相容的瀏覽器中需要使用hasAttribute()方法,而在IE7-中需要使用特性的specified屬性

  如果表單中包含<fieldset>元素,則該元素會出現在元素集合中,但沒有type屬性。因此,如果type屬性未定義,則不需要對其進行序列化。同樣,對於各種按鈕以及檔案輸入欄位也是如此(檔案輸入欄位在表單提交過程中包含檔案的內容;但是,這個欄位是無法模仿的,序列化時一般都要忽略)

  對於選項按鈕和複選框,要檢查其checked屬性是否被設定為false,如果是則退出switch語句。如果checked屬性為true,則繼續執行default語句,即將當前欄位的名稱和值進行編碼,然後添加到parts數組中。函數的最後一步,就是使用join()格式化整個字串,也就是用和號來分隔每一個表單欄位

  最後,serialize()函數會以査詢字串的格式輸出序列化之後的字串

function serialize(form){            var parts = [],field = null,option,optValue;    for (var i=0, len=form.elements.length; i < len; i++){        field = form.elements[i];        switch(field.type){            //單選或多選的<select>控制項            case "select-one":            case "select-multiple":                //如果該<select>控制項設定為name屬性                  if (field.name.length){                    for (var j=0,optLen = field.options.length; j < optLen; j++){                        //選擇<option>控制項                        option = field.options[j];                        //如果該<option>控制項被選中                        if (option.selected){                            optValue = "";                            //測試<option>控制項的value屬性,如果沒有設定,則讀取其text屬性                            //IE7-瀏覽器不支援hasAttribute()                            if (option.hasAttribute){                                optValue = (option.hasAttribute("value") ? option.value : option.text);                            } else {                                optValue = (option.attributes["value"].specified ? option.value : option.text);                            }                            //將鍵和值分別進行編碼並用‘=‘串連起來                            parts.push(encodeURIComponent(field.name) + "=" + encodeURIComponent(optValue));                        }                    }                }                break;                           case undefined:     //fieldset            case "file":        //file input            case "submit":      //submit button            case "reset":       //reset button            case "button":      //custom button                break;                            case "radio":       //radio button            case "checkbox":    //checkbox                //如果沒有選中項                if (!field.checked){                    break;                }                              default:                              if (field.name.length){                    parts.push(encodeURIComponent(field.name) + "=" + encodeURIComponent(field.value));                }        }    }            return parts.join("&");}
<form name="form" action="test.php">    <input type="text" value="123" name="text">    <select name="color"  multiple>        <option>紅</option>        <option>綠</option>        <option>藍</option>    </select>    <input type="radio" name="gender" id="male" value="male"><label for="male">男</label>    <input type="radio" name="gender" id="female" value="female"><label for="female">女</label>    <input type="checkbox" name="time" value="12" id="t12"><label for="t12">12小時</label>    <input type="checkbox" name="time" value="24" id="t24"><label for="t24">24小時</label>    <button name="btn" type="button">按鈕</button></form><div id="result"></div><script>var oForm = document.forms.form;oForm.onchange = function(e){    e = e || event;    result.innerHTML = serialize(form);}</script>

 

 

FormData

  當HTML表單同時包含檔案上傳元素和其他元素時,瀏覽器不能使用普通的表單編碼而必須使用稱為“multipart/form-data”的特殊Content-Type來用POST方法提交表單。這種編碼包括使用長“邊界”字串把請求主體分離成多個部分。對於文本資料,手動建立“multipart/form-data”請求主體是可能的,但很複雜

  XMLHttpRequest 2級為此定義了FormData類型。FormData為序列化表單以及建立與表單格式相同的資料(用於通過XHR傳輸)提供了便利

  [注意]IE9-瀏覽器不支援

【建構函式】

new FormData (form? : HTMLFormElement)

  選擇性參數form表示一個HTML表單元素,可以包含任何形式的表單控制項,包括檔案輸入框

【append()】

  append()方法用於給當前FormData對象添加一個鍵/值對

void append(DOMString name, Blob value, optional DOMString filename);void append(DOMString name, DOMString value);

  參數值name表示欄位名稱;參數值value表示欄位值;參數值filename(可選)用於指定檔案的檔案名稱,當value參數被指定為一個Blob對象或者一個File對象時,該檔案名稱會被發送到伺服器上,對於Blob對象來說,這個值預設為"blob"

【其他不常用方法】

  get():通過get(key)/getAll(key)來擷取對應的value

  set():通過set(key,value)修改資料,如果指定的key不存在則新增一條,如果存在,則修改對應的value值

  has():通過has(key)來判斷是否對應的key值

  delete():通過delete(key)來刪除資料

  [注意]以上4個不常用方法,IE瀏覽器都不支援

var oData1 = new FormData();console.log(oData1.has(‘a‘));//falseoData1.append(‘a‘,1);console.log(oData1.has(‘a‘));//trueconsole.log(oData1.get(‘a‘));//1oData1.set(‘a‘,2);oData1.append(‘a‘,1);console.log(oData1.get(‘a‘));//2console.log(oData1.getAll(‘a‘));//["2", "1"]oData1.delete(‘a‘);console.log(oData1.get(‘a‘));//null
<form action="#" name="form1">    <input type="text" value="1" name="a"></form><script>var oData1 = new FormData(document.forms.form1);console.log(oData1.has(‘a‘));//trueconsole.log(oData1.get(‘a‘));//1oData1.append(‘a‘,2);console.log(oData1.get(‘a‘));//1console.log(oData1.getAll(‘a‘));//[‘1‘,‘2‘]</script>

  一般地,我們使用FormData()建構函式建立FormData對象,然後按需多次調用這個對象的append()方法把個體“部分”(可以是字串、File或Blob對象)添加到請求中。最後,把FormData對象傳遞給send()方法,通過XHR對象將其發送到伺服器

  [注意]multipart/form-data只能用於post方式

<form action="#" name="form1"><select name="a">    <option value="1">1</option>    <option value="2">2</option>    <option value="3">3</option></select></form><div id="result"></div><script>var oForm = document.forms.form1;oForm.onchange = function(){    //建立xhr對象    var xhr;    if(window.XMLHttpRequest){        xhr = new XMLHttpRequest();    }else{        xhr = new ActiveXObject(‘Microsoft.XMLHTTP‘);    }    //非同步接受響應    xhr.onreadystatechange = function(){        if(xhr.readyState == 4){            if(xhr.status == 200){                //實際操作                result.innerHTML = xhr.responseText;            }        }    }    //發送請求    xhr.open(‘post‘,‘t1.php‘ ,true);    xhr.send(new FormData(form1)); }</script>

 

深入理解ajax系列第四篇

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.