在過去,原生的 XMLHttpRequest
在取得資料上,僅提供 responseText
與 responseXML
兩個特性,如果想接收其他的格式,例如 JSON,要以 responseText
取得純文件資料,然後使用 JSON 相關 API 來剖析為物件,如果要取得二進位資料,要 overrideMimeType("text/plain; charset=x-user-defined")
,並在取得 responseText
之後,透過字串的 charCodeAt
逐一取得字元,並處理為二進位數值。
在 XMLHttpRequest Level 1 規範中,增加了 responseType
,可用來指定回應的類型,可設定的數值有 'arraybuffer'
、'blob'
、'document'
、'json'
與 'text'
,預設值為空字串,可透過 response
取得對應的 ArrayBuffer
、Blob
、HTML DOM、JSON 物件與字串。
以接收 JSON 為例,以下會提示可搜尋的選項(沒有真的有搜尋功能就是了),如果有符合的選項,則會以 JSON 的格式傳回字串陣列,例如 '["caterpillar", "ceo"]'
這樣的格式(範例的伺服端上可搜尋的字串有 "caterpillar"
、"car"
、"ceo"
、"c++"
、"justin"
、"java"
、"javascript"
)。
你必須知道搜尋輸入方塊的位置,以讓選項對齊在輸入方塊下方,這邊使用〈封裝樣式處理〉中的第三個範例改寫:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<style type="text/css">
div {
color: #ffffff;
background-color: #ff0000;
border-width: 1px;
border-color: black;
border-style: solid;
position: absolute;
}
</style>
</head>
<body>
<hr>
搜尋:<input id="search" type="text">
<script type="module">
import x from './js/XD-1.2.0.js';
let doc = x(document);
let search = doc.elemsById('search');
search.addEvt('keyup', evt => {
doc.elemsByTag('div').remove();
let value = search.val();
// 沒有輸入值,直接結束
if(value === '') {
return;
}
let xhr = new XMLHttpRequest();
xhr.open('GET', `ResponseType-1.php?keyword=${value}`);
xhr.responseType = 'json'; // 回應是 JSON
xhr.onload = function(evt) {
let request = evt.target;
if(request.status === 200) {
// response 會是 JSON 物件
let keywords = request.response;
// 字串陣列長度不為0時加以處理
if(keywords.length !== 0) {
let innerHTML = keywords.map(keyword => `${keyword}<br>`)
.join('');
let offset = search.offset();
let offsetWidth = search.attr('offsetWidth');
let offsetHeight = search.attr('offsetHeight');
// 建立容納選項的<div>
let div = x('div').toElemCollection()
.html(innerHTML)
.css({
left : `${offset.x}px`,
top : `${offset.y + offsetHeight}px`,
width : `${offsetWidth}px`
});
document.body.appendChild(div.get());
}
}
};
xhr.send(null);
});
</script>
</body>
</html>
為了簡化範例,使用了〈封裝樣式處理〉的程式庫封裝成果,而 XMLHttpRequest
的部份為原生操作,最主要的地方在於 xhr.responseType = 'json'
,並透過 let keywords = request.response
取得了傳回的 JSON 物件,伺服端會傳回 JSON 的陣列格式,因此 keywords
會是 Array
。
這個例子沒有考慮使用者打字速度,因此每鍵一個字就會發出一次請求,你可以試著設定時間,例如一秒才發出一次,以避免使用者打字速度過快,頻繁發出請求的問題。
另外,對於每個選項,你還可以加上滑鼠點選事件,在使用者點選項目時,將項目值設定至輸入方塊,並移除 <div>
,這些額外工作,可以自行練習看看。
若想以 POST
傳送 JSON 給伺服端,請求標頭 'Content-Type'
建議設為 'application/json'
。當然,伺服端要能夠剖析 JSON 字串以取出資料,但無需親自撰寫,http://www.json.org/ 網站中提供許多語言實作的 JSON 剖析器,可協助剖析 JSON。