什麼是AJAX
AJAX 是一種用於創建快速動態網頁的技術
傳統的網頁(不使用 AJAX)如果需要更新內容,必需重載整個網頁面
AJAX通過在後臺與服務器進行少量數據交換,AJAX可以使網頁實現異步更新。這意味着可以在不重新加載整個網頁的情況下,對網頁的某部分進行更新
有很多使用 AJAX 的應用程序案例:新浪微博、Google 地圖、開心網等等等
底層原理:
AJAX的使用
1.請求對象的創建(做瀏覽器兼容)
所有現代瀏覽器new XMLHttpRequest()
老版本的瀏覽器(IE5,IE6) new ActiveXObject("Microsoft.XMLHTTP")
//如果瀏覽器有XMLHttpRequest這個對象就創建
if(window.XMLHttpRequest){
http=new XMLHttpRequest()
}
//沒有就創建ActiveXObject
else{
http=new ActiveXObject("Microsoft.XMLHTTP")
}
2.發送請求
http.open(method,url,async)//1.方法 2.url 3.異步否
http.send()//發送
3.監聽狀態
http.readyState//0:請求沒有初始化 1:服務器建立連接 2:請求已接受 3:請求處理ing 4:請求完成,響應已經就緒
http.status//200:"OK" 404:錯誤
http.onreadystatechange=function(){}//每次當狀態改變都會調用這個方法
4.響應
http.responseXML//如果服務器響應的是xml,就用這個屬性
http.responseText//如果服務器響應的是非xml,就用這個
<body>
<button id="btn1">發送</button>
<script>
window.οnlοad=function(){
var btn=document.querySelector('#btn1')
btn.οnclick=function (){
if(window.XMLHttpRequest){
http=new XMLHttpRequest()
}
//沒有就創建ActiveXObject
else{
http=new ActiveXObject("Microsoft.XMLHTTP")
}
http.open('GET','ajax.txt',true)
http.send()
http.onreadystatechange=function(){
if(http.readyState==4 && http.status==200){
console.log(http.responseText)
}else{console.log(http.readyState);console.log(http.status)}
}
}
}
</script>
</body>
GET,POST
1.GET的信息放在url中暴露出來,可以被本地緩存(根據url)
①
http.open(‘GET’,’test.txt?name=jack&pwd=123’,true)//這時候,在服務器的req.url裏就可以得到用戶名和密碼(jack如果寫成中文,就要用encodeURI(xxx)這樣服務器纔不是亂碼)
②
把服務器的數據改了,再次刷新,會發現瀏覽器得到的數據並沒有改變,咦~~其實是因爲,請求一樣時,瀏覽器是從緩存中提取的數據(用ie測試,谷歌可能不會有這個效果)//解決方案,在請求url後面加上一個隨機數或者時間戳,保證每次的url唯一
2.POST
① post請求,傳遞的數據不要放在url中,數據放在send()方法裏//send(‘name=karen&age=46’)
② post請求,要在head中告訴後端發送的數據格式(enctype)//忘了就查表單的編碼格式
③ post請求不會有緩存
後端代碼:
var http=require('http')
var fs=require('fs')
var querystring=require('querystring')
http.createServer(
function(req,res){
if(req.url=='/'){
fs.readFile('ajax3/ajax3.html',function(err,data){
res.end(data.toString())
})
}
else if(req.method.toUpperCase()=='POST'){
var postArg='';
req.on('data',function(data){postArg+=data})
req.on('end',function(){
var userData=querystring.parse(postArg)
console.log(userData)
var person1_json="{'你的密碼':"+userData["pwd"]+"}"
res.end(person1_json)
})
}
}
).listen(8081)
前端代碼:
<body>
<button id="btn1">post請求</button>
<formenctype="application/x-www-form-urlencoded">
<script>
var btn1=document.getElementById('btn1')
btn1.οnclick=function(){
varhttp;
if(window.XMLHttpRequest){http=newXMLHttpRequest()}
else{http=newActiveXObject("Microsoft.XMLHTTP")}
http.open('POST','ajax3.txt',true)
http.setRequestHeader('content-type','application/x-www-form-urlencoded;charset=utf-8')
http.send("name=jack&pwd=123")
http.onreadystatechange=function(){
if(http.readyState==4&& http.status==200){
console.log(http.responseText)
}else{console.log(111)}
}
}
</script>
</body>
數據解析
這裏我們用假數據講解數據解析(引出跨域問題)
1.得到數據以後,我們怎麼把數據通過DOM操作展示出來呢
最直接的辦法就是把返回的數據,通過字符串的方法各種剪裁然後展示
得到的數據:var person=“{name:jack,age:18,info:[‘html’,’css’,’js’,’php’]}”
解析:
var name=person.slice(6,10)..........
Document.get...(‘name’).innerHTML=name..........
2.JSON解析
//爲何json解析:因爲做開發時json的數據多如牛毛
①一層
<body>
<button>登錄</button><br/>
<p id="name"></p>
<p id="age"></p>
<p id="phoneNumber"></p>
<script>
document.querySelector("button").οnclick=function(){
varpersonstr='{"name":"jack","age":"19","phoneNumber":"18282832341"}'
var person_json=JSON.parse(personstr)
document.getElementById('name').innerHTML='姓名:'+person_json.name
document.getElementById('age').innerHTML='年齡:'+person_json.age
document.getElementById('phoneNumber').innerHTML='電話:'+person_json.phoneNumber
}
</script>
</body>
②兩層
<body>
<button>登錄</button><br/>
<p id="name"></p>
<p id="age"></p>
<p id="phoneNumber"></p>
<p id="it"></p>
<script>
document.querySelector("button").οnclick=function(){
varpersonstr='{"name":"jack","age":"19","phoneNumber":"18282832341","it":["html","css","js","php"]}'
var person_json=JSON.parse(personstr)
document.getElementById('name').innerHTML='姓名:'+person_json.name
document.getElementById('age').innerHTML='年齡:'+person_json.age
document.getElementById('phoneNumber').innerHTML='電話:'+person_json.phoneNumber
for (i in person_json.it){
document.getElementById('it').innerHTML+=" "+person_json.it[i]
}
}
</script>
</body>
③管你多少層
<body>
<button>登錄</button><br/>
<p id="name"></p>
<p id="age"></p>
<p id="phoneNumber"></p>
<p id="it"></p>
<p id="QQ"></p>
<script>
document.querySelector("button").οnclick=function(){
varpersonstr='{"name":"jack","age":"19","phoneNumber":"18282832341","it":["html","css","js","php"],"QQ":[{"id":"2733464076","pwd":"xxx1"},{"id":"12345","pwd":"xxx2"}]}'
var person_json=JSON.parse(personstr)
console.log(person_json)
document.getElementById('name').innerHTML='姓名:'+person_json.name
document.getElementById('age').innerHTML='年齡:'+person_json.age
document.getElementById('phoneNumber').innerHTML='電話:'+person_json.phoneNumber
for (i in person_json.it){
document.getElementById('it').innerHTML+=" "+person_json.it[i]
}
for (i in person_json.QQ){
for(j inperson_json.QQ[i]){
document.getElementById('QQ').innerHTML+=" "+person_json.QQ[i][j]
}
}
}
</script>
</body>
④結合服務器
html:
<body>
<button>登錄</button><br/>
<p id="name"></p>
<p id="age"></p>
<p id="phoneNumber"></p>
<p id="it"></p>
<p id="QQ"></p>
<script>
document.querySelector("button").οnclick=function(){
//兼容性
varhttp;
if(window.XMLHttpRequest){http=newXMLHttpRequest()}
else{http=newActiveXObject("Microsoft.XMLHTTP")}
//請求數據
http.open('GET','ajax4.txt',true)
http.send()
//得到數據
http.onreadystatechange=function(){
if(http.readyState==4&& http.status==200){
console.log(http.responseText)
//解析數據並展示
ui(http.responseText)
}else{console.log(111)}
}
function ui(personstr){
var person_json=JSON.parse(personstr)
console.log(person_json)
document.getElementById('name').innerHTML='姓名:'+person_json.name
document.getElementById('age').innerHTML='年齡:'+person_json.age
document.getElementById('phoneNumber').innerHTML='電話:'+person_json.phoneNumber
for (i in person_json.it){
document.getElementById('it').innerHTML+=" "+person_json.it[i]
}
for (i in person_json.QQ){
for(j inperson_json.QQ[i]){
document.getElementById('QQ').innerHTML+=" "+person_json.QQ[i][j]
}
}
}
}
</script>
</body>
服務器:
var http=require('http')
var fs=require('fs')
http.createServer(
function(req,res){
if(req.url=='/'){
fs.readFile('ajax4/ajax4.html',function(err,data){
res.end(data.toString())
})
}
elseif(req.method.toUpperCase()=='GET'&&req.url=='/ajax4.txt'){
res.end('{"name":"jack","age":"19","phoneNumber":"18282832341","it":["html","css","js","php"],"QQ":[{"id":"2733464076","pwd":"xxx1"},{"id":"12345","pwd":"xxx2"}]}')
}
}
).listen(8081)
⑤MV:model-view
⑥:解析到這裏你應該發現一個問題:爲什麼每次,我都是把前端的界面通過服務器發送過來,再做AJAX局部數據請求並展示,可以直接自己寫個前端界面(代碼一樣),然後來我的服務器拿數據刷新局部界面嗎?跨域
1.跨域,
一個域名下的文件,AJAX去請求另外一個域名下的文件就跨域了,它是由瀏覽器的同源策略造成的,是瀏覽器對JavaScript施加的安全限制
2.怎麼看當前界面是不是屬於其他網站的呢
主要從這幾個參數看是否同源
所謂同源是指,域名,協議,端口均相同(任一一個不同都屬於跨域)
http://www.hq.com?name=jack想訪問https://www.baidu.com?ajax.php
http協議不同:http https
子域名同:www www
主域名不同:hq baidu
3.JSONP解決跨域
①JSONP:JSON with Padding //嵌入的JSON數據
②除了AJAX可以獲取資源,flash也可以獲取資源,還有一個就是我們最常見的也可以獲取資源---標籤! img標籤 link 標籤 script標籤等等
③JSONP不是新東西,就是以前學過的東西,做點小操作實現跨域
⑤複習script標籤
script標籤可以加載資源:<scriptsrc=’test.js’></script>
script標籤加載資源沒有跨域問題:用百度地圖的API的時候,<scripttype="text/javascript"src="http://api.map.baidu.com/api?v=2.0&ak=您的密鑰">
<script src=’txt.js’></script>//這裏我們加載的是不是js文件呢?
文件類型:文件是什麼類型的由誰來決定? 不是後綴,如果是後綴的話,那我們隨便把txt文件後綴改爲png,那豈不是txt數據就變成圖片數據了,後綴只是取了個名字讓別人或者別的程序讀,告訴依賴者我的內容可能是什麼格式的//把js文件後綴改了,讓script標籤加載
文件的類型由文件內容本身決定
<script src=’test.txt’></script> src裏的東西,不管是什麼格式,它都會去加載,只是,加載了之後我們要使用得是js的東西
⑥JSONP的原理
如果加載的js資源裏是這樣滴
var a=[10,20,30]
那我們加載以後想使用20,直接叫一下a再取對應下標就可以得到,
但是,如果js資源裏是這樣的[10,20,30]
這時候我們依然可以加載到這個數組數據,但是想使用20,該如何使用(最悲劇的事情就是工資到手了不能用)
沒有名字還想用,瞬間想到有一種情況就是這樣的,函數調用時,傳遞的回調函數就可以沒有名字,因爲函數爲它取了一個形參名
因此我們可以這樣做,就能達到不給數組取名字就能使用它
js文件:
fn([10,20,30])
html文件:
function fn(arg){//使用數據20}
<script src=’test.js’></script>
這,就是JSONP的原始模式:在資源加載進來之前定義好一個函數,這個函數接受一個參數(數據),函數裏面利用這個參數就可以使用數據了,然後需要的時候通過script標籤加載對應的遠程文件資源,當遠程文件資源被加載進來以後,就會去執行我們之前定義好的函數,並且把數據當做這個函數的實參傳入//Padding的意思就是把數據嵌入到代碼塊中(函數調用)
上面例子有一個問題,數據是頁面加載的時候去加載的數據, 而我們的局部請求往往都是用戶動了界面哪個地方數據纔來
解決方法:在用戶的事件觸發時,創建script標籤去加載數據
Js文件:
fn([10,20,30])
html文件:
function(arg){xxx1.innerHTML=arg[1]}
document .getxxx(‘btn’).οnclick=function(){
varscript1=document.createElement(‘script’)
script1.src=’test.js’
document.body.appendChild(acript1)
}
但是,還有一個問題,如果有兩個數據呢,比如,用戶點了一個按鈕局部請求並展示了20,又點擊了另外一個按鈕,局部請求並想展示另外一個數據,這時候,我們馬上想到可以多寫一個函數
html文件:
<body>
<button id="btn1">中文</button>
<p id="p1"></p>
<button id="btn2">Eglish</button>
<p id='p2'></p>
<script>
function fn1(arg){
varp1=document.getElementById("p1").innerHTML=arg[1]
}
function fn2(arg){
varp1=document.getElementById("p2").innerHTML=arg[1]
}
var btn1=document.getElementById("btn1")
var btn1=document.getElementById("btn1")
btn1.οnclick=function(){
varscript1=document.createElement("script")
script1.src='http://192.168.0.120:8081/test.js?page=1'
document.body.appendChild(script1)
}
btn2.οnclick=function(){
varscript2=document.createElement("script")
script2.src='http://192.168.0.120:8081/test.js?page=2'
document.body.appendChild(script2)
}
</script>
</body>
js文件:
var http=require('http')
http.createServer(
function(req,res){
console.log(req.url)
if(req.url=='/test.js?page=1'){res.end("fn1(['一','二','三'])")}
else{res.end("fn2(['one','two','three'])")}
}
).listen(8081)
這時候問題就來了,假設你寫界面的時候,又有一個按鈕了,你是不是又要寫一個函數fn3,然後又一天又有一個按鈕,你又要寫一個函數fn4,每有一個業務你都要去寫,假設有10萬個按鈕呢?怕不怕? 最可怕的不是累死,是後端的人把你打死,因爲你每次有新的按鈕,你都要爲它取一個名字,然後去找後端開發的再多加一個接口,還必須得把函數的名字都取一樣:fn1,fn2...,項目進行時還非得等到你寫到哪裏了,後端纔開始寫.
⑦JSONP的使用
我們最後一次優化是把回調函數的名字傳給服務器,前端把回調函數取什麼名字,後端就直接拿過來用
html文件:
<body>
<button id="btn1">中文</button>
<p id="p1"></p>
<button id="btn2">Eglish</button>
<p id='p2'></p>
<script>
function fn1(arg){
varp1=document.getElementById("p1").innerHTML=arg[1]
}
function fn2(arg){
var p1=document.getElementById("p2").innerHTML=arg[1]
}
var btn1=document.getElementById("btn1")
var btn1=document.getElementById("btn1")
btn1.οnclick=function(){
varscript1=document.createElement("script")
script1.src='http://192.168.0.120:8081/test.js1?callback=fn1'
document.body.appendChild(script1)
}
btn2.οnclick=function(){
varscript2=document.createElement("script")
script2.src='http://192.168.0.120:8081/test.js2?callback=fn2'
document.body.appendChild(script2)
}
</script>
</body>
Js文件:
var http=require('http')
var url=require('url')
http.createServer(
function(req,res){
//console.log(url.parse(req.url))
varcallback=url.parse(req.url).query.replace('callback=','')
varpathname=url.parse(req.url).pathname
var data=''
if(pathname=='/test.js1'){data=callback+"(['一','二','三'])"}
else{data=callback+"(['one','two','three'])"}
res.end(data)
}
).listen(8081)
綜合(數據的獲取與方案的選擇)
想加載這個資源到界面上,怎麼做(這就是新浪微博的數據接口,趕緊去查新浪微博的API)//如果這個能自己解決了就可以自己去學後面jQuery了
1.請求的局部數據沒有跨域(一般指自己公司的數據)
用AJAX請求數據
2.請求的局部數據如果跨域了
①去問後端(自己公司的後端,別人家公司的後端),讓他告訴你(接口文檔)JSONP請求的參數:回調函數名
比如百度搜索條的提示的JSONP接口:suggestion.baidu.com/su?wd=蓋倫&cb=fn1
②有的公司給出了JSONP接口,有的沒有給JSONP接口,比如我們一直沒有解決的這個接口(其實是個移動端的請求接口)
這時候有兩種解決方案:
one:老老實實去別人家公司的開發平臺各種同意然後引入SDK
比如新浪微博API
two:還是用AJAX請求數據,請求自己服務器的數據! 數據由自己的服務器去請求(讓後端的人寫代碼去請求,前端只管按照自己公司服務器邏輯去請求數據)
two的node代碼:
var request = require('request');
request('https://api.weibo.com/2/statuses/home_timeline.json?access_token=2.00ZmCkcDTew45B578808a592mhaj_E',function (error, response, body) {
if (!error&& response.statusCode == 200) {
console.log(JSON.parse(body))//這裏如果出數據了,說明我們自己公司的服務器有數據了,接下來就是自己去設計邏輯給前端發數據
}
})