Js_Dom(9)__Dom基础
什么是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.onload=function(){
var btn=document.querySelector('#btn1')
btn.onclick=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.onclick=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").onclick=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").onclick=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").onclick=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").onclick=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’).onclick=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.onclick=function(){
varscript1=document.createElement("script")
script1.src='http://192.168.0.120:8081/test.js?page=1'
document.body.appendChild(script1)
}
btn2.onclick=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.onclick=function(){
varscript1=document.createElement("script")
script1.src='http://192.168.0.120:8081/test.js1?callback=fn1'
document.body.appendChild(script1)
}
btn2.onclick=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))//这里如果出数据了,说明我们自己公司的服务器有数据了,接下来就是自己去设计逻辑给前端发数据
}
})