ajax背景、ajax对象、ajax状态、ajax与http、ajax请求数据接口、同步与异步、ajax请求XML数据、封装ajax函数、artTemplate简介、同源策略和跨域请求、JSONP
AJAX簡介:
ajax背景:
1.AJAX(Asynchronous JavaScript And Xml)異步的 JavaScript 和 XML:ajax是瀏覽器提供的一套API,最早出現在谷歌瀏覽器,是在瀏覽器端進行網絡編程(發送請求、接收響應)的技術方案。它可以使我們通過JavaScript直接獲取服務端最新的內容而不必重新加載頁面,讓web更接近桌面應用的體驗。
2.涉及到ajax操作的界面‘不能’使用文件協議(文件的方式)訪問,實際是可以訪問的。
3.ajax是一套API,核心提供的類型:XMLHttpRequest,其使用步驟如下:
<script>// 1.創建 XMLHttpRequest 對象,xhr就類似瀏覽器的作用(發送請求 接收響應)var xhr = new XMLHttpRequest(); //xhr變量名可以為其它名,習慣使用xhr;此對象有兼容問題,解決方法如下:// 解決ajax的IE5-6兼容問題:var xhr = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXOBject('Microsoft.XMLHTTP');// 2.打開瀏覽器輸入網址,可以是服務端任何文件,比如 .txt或.phpxhr.open('GET', 'http://day-03.io/6.Ajax練習/01.ajax的背景/time.php'); //第一個參數為請求方式,第二個參數為請求地址// 3.發送一個請求,如果是post請求方式,send里面可以傳請求體,后面詳細講:xhr.send();// 4.響應,因為客戶端永遠不知道服務端何時才能返回我們的需求響應,所以,ajax API 采用時間機制(類似通知的方式):xhr.onreadystatechange = function() {// 這里this.readyState有三個階段:2,3,4;寫在xhr.open()下面會有狀態1的出現,如果需要捕獲第一個狀態的變化,需要注意代碼執行順序的問題,有0-4五個狀態,四個階段;if (this.readyState !== 4) return;//只有狀態4表示請求響應已經完成,此時可以對數據進行操作:// 5.看結果console.log(this.responseText); //responseText可以接收到響應體,response也可以接收的響應體但是有區別};</script>ajax中五種狀態四種階段代表什么:
ajax有五個狀態,四種階段,分別代表如下xhr.readyState的返回值:
<script>var xhr = new XMLHttpRequest();console.log(xhr.readyState);// => 0:初始化,請求代理對象xhr.open('GET', 'time.php');console.log(xhr.readyState);// => 1:open 方法已經調用,建立一個與服務端特定端口的連接xhr.send();xhr.addEventListener('readystatechange', function() {switch (this.readyState) {case 2:// => 2:已經接收到了響應報文的響應頭,但是還沒有拿到體,this.getAllResponseHeaders()用來獲取響應頭console.log(this.getResponseHeader('server'));console.log(this.responseText);break;case 3:// => 3:正在下載響應報文的響應體,有可能響應體為空,也有可能不完整,這里不能保證響應體數據的完整性console.log(this.responseText);break;case 4:// => 4:一切 OK ,整個響應報文已經完整下載下來了,請求體的數據是完整的console.log(this.responseText);break;};});</script><script>var xhr = new XMLHttpRequest(); //----安裝一個瀏覽器console.log(xhr.readyState); //--------------0:初始化請求代理xhr.open('GET', 'time.php'); //打開一個瀏覽器,建立一個與服務端端口的連接console.log(xhr.readyState); //--------------1:建立一個與服務端端口的連接xhr.send(); //發送請求console.log(xhr.readyState); //--------------1// 用addEventListener()的方式注冊事件:xhr.addEventListener('readystatechange', function() {// if (this.readyState!==4) return;console.log(this.readyState); //-------------4,如果是注釋掉上面的if條件,那么這里打印的值為:2,3,4,分別表示:// 2:已經接收到響應體的響應頭,還沒有拿到響應體// 3:正在下載響應體中// 4:已經下載完一個完整的響應體console.log(this.response); //服務端響應的東西,this.responseText也可以拿到響應體// 在可以使用this的作用域建議使用this,因為這樣可避免沿著作用域鏈一級一級的向下找,優化了性能。});</script>onload事件代替readystatechange事件:
onload事件實現readystatechange事件效果:
<script>var xhr = new XMLHttpRequest();xhr.open('GET', 'time.php');xhr.send(null); xhr.onload = function() { //onload事件可以代替readystatechange事件,但是onload有兼容性問題,因此實際開發中依然不會使用onloadconsole.log(this.readyState);console.log(this.responseText);};</script>ajax遵循http協議:
ajax遵循http協議進行發送請求,在ajax中以post方式進行請求時注意:設置請求頭中content-type屬性及值,send()中以urlencoded格式設置請求體,如:
<script>var xhr = new XMLHttpRequest();xhr.open('POST', 'add.php'); //以POST的方式請求一個地址//xhr.setRequestHeader('keyA', 'valueA'); //setRequestHeader用來設置一個請求頭內容// 請求體是 urlencoded 格式的內容,一定要設置請求頭中的Content-Type 為'application/x-www-form-urlencoded'才可以正常請求:xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');xhr.send('key1=value1&key2=value2'); // 以 urlencoded 格式設置請求體</script>數據接口:
數據接口:能提供特定的能力,有輸入有輸出,返回數據的地址,如下面服務端代碼的URL:users.php即為一個數據接口,詳細如下:
服務端代碼:
<?php//這里使用假數據做測試,實際開發中可能會從數據庫獲取數據:$data=array(array('id'=>1,'name'=>'法海','age'=>39),array('id'=>2,'name'=>'如經','age'=>14),array('id'=>3,'name'=>'道號','age'=>19));//當收到ajax發送的請求是做出相應的數據返回:if(empty($_GET['id'])){// 沒有傳遞id返回所有數據,因為http協議中約定報文的內容是字符串,所以需要用json數據格式$json = json_encode($data);//==>返回json字符串:[{"id":1,"name":"法海","age":39},{"id":2,"name":"如經","age":14},{"id":3,"name":"道號","age":19}]echo $json;}else{foreach ($data as $item){if($item['id']!=$_GET['id']) continue;$json = json_encode($item);//==>[{"id":1,"name":"\u5e08\u5085","age":39}]echo $json;};};通過ajax請求數據接口的數據:
<script>var listElement = document.getElementById('list');var xhr = new XMLHttpRequest();xhr.open('GET', 'users.php?id=' + this.id); //這里可以使用?傳參請求到具體的值,若不傳入參數,則拿回所有數據遍歷;在一個readystatechange事件中可以繼續new XMLHTTPRequest()請求數據xhr.send();xhr.onreadystatechange = function() {if (this.readyState !== 4) return;var data = JSON.parse(this.responseText); //將json字符串轉換為json對象//通過遍歷的方式對數據data進行處理(渲染到頁面):for (var i = 0; i < data.length; i++) {console.log(data[i].id + '--' + data[i].name + '---' + data[i].age); //打印拿到的所有數據};};</script>responseText和response區別:
responseTexxt返回的是普通字符串的形式的數據,不能通過 xhr.responseType='數據類型’設置返回的數據類型;response可以通過 xhr.responseType='數據類型’設置返回的數據類型。
<script>var xhr = new XMLHttpRequest();xhr.open('GET', 'test.php');xhr.send();xhr.responseType = 'json'; //有兼容問題xhr.onreadystatechange = function() {if (this.readyState === 4) {// console.log(this.responseText);console.log(this.response);};};</script>通過ajax發送post請求:
以post方式提交數據,需要注意:如果請求體是urlencoded格式,需要設置請求頭的content-type,如:
以post方式通過ajax提交密碼和用戶名:
<script>// 假設給按鈕注冊點擊事件執行ajax請求提交數據:getElement('btn').onclick = function() {// 假設獲取input中的值并給變量:var username = getElement('username').value;var password = getElement('password').value;var xhr = new XMLHttpRequest(); //在js中開啟一個瀏覽器xhr.open('POST', 'data.php'); //打開瀏覽器并訪問data.php//如果請求體是 urlencoded 格式 必須設置請求頭為:Content-Type','application/x-www-form-urlencoded'xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');// xhr.send('username=' + username + '&password=' + password),發送請求體,字符串拼接不好操作,推薦使用模板字符串:xhr.send(`username=${username}&password=${password}`);// 3. 根據服務端的反饋 作出界面提示xhr.onreadystatechange = function() {if (this.readyState !== 4) return;console.log(this.responseText); //若服務端有數據返回,則接收(服務端各個處理的反饋)};};</script>服務端對用戶名和密碼做校驗并做反饋:
<?php// 判斷是否提交數據并做出反饋:if(empty($_POST['username'])||empty($_POST['password'])){exit('請提交用戶名和密碼');};// 接收客戶端傳過來的數據并給變量:$username=$_POST['username'];$password=$_POST['password'];// 校驗數據:通常使用數據庫中的數據,這里使用假數據做測試:if($username==='admin' && $password==='123'){exit('登錄成功!');};exit('用戶名或者密碼錯誤');同步與異步模式:
同步模式:在相同的時間內只能做一件事情,ajax 操作會有楞等的情況,區別在于 send 方法會不會出現等待情況;
異步模式:在相同的時間內可以做不同的事情,比起同步模式,異步處理時間更短,但是時間差異不是很大,一般需要使用console.time()方法進行測試時間。
xhr.open()中的第三個參數async是控制是否開啟異步模式,值為布爾值,默認是true則表示異步;
<script>// 同步模式,加載時間長var xhrSync = new XMLHttpRequest()// open 方法的第三個參數是 async 可以傳入一個布爾值,默認為 truexhrSync.open('GET', 'time.php', false) //關閉異步模式console.time('sync')xhrSync.send() //關閉異步模式后,等待請求響應的過程完全完成后再繼續console.log(xhrSync.responseText)// console.log('end request')console.timeEnd('sync')// 異步模式,加載時間短var xhrSync = new XMLHttpRequest()// open 方法的第三個參數是 async 可以傳入一個布爾值,默認為 truexhrSync.open('GET', 'time.php', true) //打開異步模式,默認是打開的console.time('sync')xhrSync.send()console.log(xhrSync.responseText)// console.log('end request')console.timeEnd('sync')</script>ajax請求XML數據:
XML數據格式類似存在html標簽中的內容,但是標簽需要大寫,文件后綴名為xml;ajax請求服務端xml數據時,需要指明響應頭中content-type為application/xml,如:
ajax請求代碼:
<script>// 一般服務端響應一個簡單的數據就是一個字符串,如果想要返回一個復雜的數據,一般采用json的格式;但是有很多老項目采用xml的方式存數據,此時也是需要獲取數據的,如:// ajax請求XML格式的數據:var xhr = new XMLHttpRequest();xhr.open('GET', 'xml.php');xhr.send();xhr.onreadystatechange = function() {if (this.readyState !== 4) return;// this.responseXML 是專門用于獲取服務端返回XML數據的,操作方式就是通過DOM(節點)的方式操作,但是需要服務端響應頭中的 Content-Type 必須是 application/xml// header('Content-Type: application/xml');---需要服務端響應頭中的 Content-Type 必須是 application/xmlconsole.log(this.responseXML.documentElement.children[0].innerHTML)console.log(this.responseXML.documentElement.getElementsByTagName('name')[0])}</script>服務端XML數據:
<?phpheader('Content-Type: application/xml');//告知響應頭中響應文檔類型為xml?><?xml version="1.1" encoding="utf-8"?><person><name>小明</name><age>14</age><gender>男</gender></person><!-- 上面不能有空行,否則報錯 -->封裝ajax函數:
實際開發中使用ajax獲取數據的地方很多,為了節省開發成本,一般是將ajax封裝成一個函數,使用時調用即可,我封裝了一個名為ajax的AJAX數據請求函數,其中參數解釋為:
method:必須,請求方式,
url:必須,請求路徑
askbody:可選參數,當不需要向服務端傳入參數時,可以給null占位,但是不能不寫
callback:必須,一個用來處理響應數據的回調函數,回調函數中的參數即為響應結果
<script>function ajax(method, url, askbody, callback) {method = method.toUpperCase(); //當調用者輸入的請求方式為小寫字母時轉大寫var xhr = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXOBject('Microsoft.XMLHTTP'); //解決兼容問題//默認請求體是字符串形式的,當調用者輸入的是對象形式時,需要轉換為字符串形式:if (typeof askbody === 'object') {var arr = []; //定義一個空數組用來對askbody進行拆解再拼接為字符串for (var key in askbody) {var value = askbody[key]; //通過遍歷的的方式將請求體對象中的鍵拿到,并使用[鍵]的方式將對應的值拿到給變量valuearr.push(key + '=' + value); //將鍵和值作為一組元素追加到數組中};askbody = arr.join('&'); //將數組每個元素之間用&符號分割后轉換為字符串形式,并重新給askbody,join可以將數組轉化為字符串,括號中加參數則表示給每個元素之間添加的字符。};//如果是以get方式請求:將url和askbody進行拼接:if (method === 'GET') {url += '?' + askbody;};xhr.open(method, url);//需要以post請求時,定義一個變量data接收請求體;當為get方式請求時,因為下面send中傳入null或者不傳,因此這里需要將data變量提升到整個函數作用域并初始值為null:var data = null;if (method === 'POST') { //當以post請求時,需要傳入請求體,如下:data = askbody; //將上面處理好的askbody賦值給data變量供下面send中使用xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded"); //當為post請求時,必須設置請求頭中的Content-Type的值為application/x-www-form-urlencoded,且此代碼要放到open的后面,否則會報錯};xhr.send(data);xhr.addEventListener('readystatechange', function() {if (this.readyState === 4) {callback = callback || function() {alert('請傳入數據處理回調函數');};callback(this.responseText);};});};//以get方式調用ajax:ajax('GET', 'time.php', null, function(result) {console.log(result);});//以post方式調用ajax:ajax('POST', 'add.php', {key1: 'value1',key2: 'value2'}, function(result) {console.log(result);});</script>artTemplate引擎模板:
模板引擎實際上就是一個 API,模板引擎有很多種,使用方式大同小異,目的為了可以更容易的將數據渲染到 HTML中,這里采用artTemplate:https://aui.github.io/art-template/ 介紹,其文件實際是一個js文件。
模板屬性位置:
模板寫在script標簽中,模板寫在js中不便于維護;script標簽的特點:1.innerHTML永遠不會顯示在界面上 2.如果script標簽type屬性的值不為 text/JavaScript 時,內部的內容不會作為JavaScript執行;
特別提醒:
在art-template內部是不能訪問到外面的變量的,如果一定要訪問的話,可以使用其提供的輔助方法將外面的變量賦值給內部變量。
使用步驟:
// 1.選擇一個模板引擎,去百度搜索,并引入這個模板的js文件:<script src='template-web.js'></script>// 2.準備一個模板 : each遍歷數據,$value拿到的是當前被遍歷的那個數據,{{}}中定義某個數據或模板語法,其他地方依然可以寫HTML<script id="tmpl" type="text/x-art-template">{{each comments}}//comments為下面content中comments,注意名字一致:<tr><td>{{$value.id}}</td><td>{{$value.author}}</td><td>{{$value.content}}</td></tr>{{/each}}</script>// 3.下面將通過ajax獲取數據,并將數據提供給art-template模板,之后在渲染到dom中:<script>var xhr = new XMLHttpRequest();xhr.open('GET', 'test.php');//test.php中返回數據xhr.send();xhr.onreadystatechange = function() {if (this.readyState === 4) {var res = JSON.parse(this.responseText);//3-1:將獲取到的數據給tmpl模板中的comments:var content = {comments: res.data};//3-2:使用art-template模板引擎的API:template()將模板和數據整合得到渲染結果并賦值給變量:var html = template('tmpl', content); //3-3:將要渲染的結果渲染到某dom元素中:(這里渲染到id名為box的div中)document.getElementById('div').innerHTML = html;};};</script>// 4.例如:在art-template中是無法訪問到$ (jQuery)這個變量的,如果想要訪問到此變量,那么可以使用art-template提供的輔助方法:template.helper('art-template中變量名',function(){return jQuery;}),在使用時需要調用變量名,如:<script>template.helper('jqueryinart',function(){return jQuery;});</script><script id="tmpl" type="text/x-arttemplate">{{var $ = jqueryinart()}};</script>同源策略和跨域請求:
同源: 協議 域名 端口相同的URL地址 同源策略: 不同源地址之間, 默認是不能相互發送ajax請求,后面有解決方案 不同源地址之間如果要相互請求, 必須服務端和客戶端配合才可以 同源或者不同源說的是兩個地址之間的關系, 不同源地址之間請求我們稱之為跨域請求 現代化的 Web 應用中肯定會有不同源的現象, 所以必然要解決這個問題, 從而實現跨域請求。跨域請求:
<body><!-- link 真正的定義:鏈入一個文檔,通過 rel 屬性申明鏈入的文檔與當前文檔之間的關系 --><!-- <link rel="stylesheet" href="nprogress.css"> --><script>// 請求一個不同源的地址實際上就是我們所說的跨域請求// 校驗目標:1 能發出去,2 能收回來// 可以發送請求的標簽:img link script iframe// ## 1. img// 可以發送不同源地址之間的請求// 無法拿到響應結果// var img = new Image()// img.src = 'http://test.com/categories'// ## 2. link// 可以發送不同源地址之間的請求// 無法拿到響應結果// var link = document.createElement('link')// link.rel = 'stylesheet'// link.href = 'http://test.com/categories'// document.body.appendChild(link)// ## 3. script// 可以發送不同源地址之間的請求// 無法拿到響應結果,但是借助于JS能夠執行var script = document.createElement('script')script.src = 'http://test/time.php'document.body.appendChild(script) // 開始發起請求 // 相當于請求的回調,在服務端定義一個函數調用如:echo "foo({$json}})"function foo(res) {console.log(res)}</script></body>JSONP:
通過 script 標簽請求一個服務端的 PHP 文件,這個文件返回的結果是一段JS,php文件作用是調用我們事先定義好的一個函數,從而將服務端想要給客戶端發過去的數據以函數參數的形式發送給客戶端
<script src="http://test/data.php"></script><script>function myonload (data) {console.log(data)}</script>服務端代碼:
<?phpecho 'myonload({'time':12231234})';?>封裝jsonp函數:
實際開發中可能多次會用到跨域請求,此時為了節約開發成本,封裝jsonp函數,其參數解釋:
url:必須,請求的路徑;
param:可選參數,用于請求時傳入參數;
callback:必須,對響應回來的數據進行處理的回調函數,回調函數中的參數即為服務端響應回來的數據;
<script>function jsonp(url, param, callback) {var functionName = 'JSONP_' + Date.parse(new Date()); //函數調用時定義一個不同的變量名if (typeof param === 'object') { //判斷param參數是否是對象,若是的還將對象的形式轉化為字符串形式var arr = [];for (var key in param) { //通過遍歷的方式將param中的對象的每一個項的鍵和值拼接var value = param[key];arr.push(key + '=' + value);};param = arr.join('&'); //將數組轉化為字符串形式,并且數組每個元素之間使用&分割};var script = document.createElement('script'); //創建一個script標簽script.src = url + '?' + param + '&callback=' + functionName; //設置script標簽的src屬性值,以?傳參的形式傳入請求字符(包括函數名給服務端)//例如URL: 'http://test/server.php?name=jack&callback=JSONP_80284020025document.body.appendChild(script); //將script標簽追加到body中,此時對地址URL發起請求window[functionName] = function(data) { //window.JSONP_80284020025=function(){};服務端對window.JSONP_80284020025函數進行調用且傳入了服務端的數據$resultData實參callback(data); //data為函數window.JSONP_80284020025的形參,同時為回調函數callback的實參// (function(result) {//result為回調函數callback的形參// console.logg(result)// })(data);//data此時作為實參供回調函數處理delete window[functionName]; //當處理完數據后釋放內存,并刪除script標簽document.body.removeChild(script);};};// 調用:jsonp('http://test/server.php', {id: 123}, function(result) {console.log(result)});</script>服務端代碼:
<?php$data = time();// 如果客戶端采用的是 script對服務器發送的請求, 一定要返回一段 JavaScript,設置Content-Type為application/javascriptheader('Content-Type: application/javascript');$resultData = json_encode($data);$callback = $_GET['callback'];//接收到函數名JSONP_80284020025echo "typeof {$callback} === 'function' && {$callback}({$resultData})";//如果JSONP_80284020025為函數類型,則調用JSONP_80284020025函數,并將請求的數據作為函數參數傳給函數處理提示:本文圖片等素材來源于網絡,若有侵權,請發郵件至郵箱:810665436@qq.com聯系筆者刪除。
筆者:苦海
總結
以上是生活随笔為你收集整理的ajax背景、ajax对象、ajax状态、ajax与http、ajax请求数据接口、同步与异步、ajax请求XML数据、封装ajax函数、artTemplate简介、同源策略和跨域请求、JSONP的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 电脑显示器不亮主机正常_电脑主机已开机
- 下一篇: secure连不上远程地址_[笔记]Ma