一、Ajax(part1)
Ajax即“Asynchronous Javascript And XML”(异步JavaScript和XML),是指一种创建交互式网页应用的网页开发技术,AJAX = 异步 JavaScript和XML(标准通用标记语言的子集),AJAX 是一种用于创建快速动态网页的技术。通过在后台与服务器进行少量数据交换,AJAX 可以使网页实现异步更新。这意味着可以在不重新加载整个网页的情况下,对网页的某部分进行更新。传统的网页(不使用 AJAX)如果需要更新内容,必须重载整个网页页面。
1、初识
1 $.ajax({ 2 url: '/host', # 数据提交地址 3 type: "POST", # 提交类型 4 data: {'k1': 123, 'k2': "root"}, # 提交的内容 字典格式 5 success: function(data){ # 客户端会一直等待服务端返回的数值 6 # data是服务器端返回的字符串 7 var obj = JSON.parse(data); 8 } 9 }) 10 11 # 建议:永远让服务器端返回一个字典 12 return HttpResponse(json.dumps(字典))
2、简单的前后端交互
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<div class="shade hide"></div> <div class="add-modal hide"> <form method="POST" action="/home/"> <div class="group"> <input id='host' type="text" placeholder="主机名" name="hostname" /> </div> <div class="group"> <input id='ip' type="text" placeholder="IP" name="ip" /> </div> <div class="group"> <input id='port' type="text" placeholder="端口" name="port" /> </div> <div class="group"> <select id='sel' name="b_id"> {% for op in b_list %} <option value="{{ op.id }}">{{ op.caption }}</option> {% endfor %} </select> </div> <input type="submit" value="提交" /> <a id="ajax_submit">要上天提交</a> <input id="cancel" type="button" value="取消" /> </form> </div>
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
$(function(){
$('#ajax_submit').click(function () {
$.ajax({
url:"/test_ajax/",
type:"POST",
data:{'hostname':$('#host').val(),'ip':$('#ip').val(),'port':$('#port').val(),'b_id':$('#sel').val()},
success:function (data) {
if(data=='OK'){
location.reload() // 重新加载页面
}else {
alert(data);
}
}
})
})
})
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
def test_ajax(request): print(request.method) h = request.POST.get('hostname') i = request.POST.get('ip') p = request.POST.get('port') b = request.POST.get('b_id') print(h,i,p,b) if h and len(h) > 5: # 主机名长度判断 models.Host.objects.create(hostname=h,ip=i,port=p,b_id=b) # 创建数据 return HttpResponse("OK") # 返回OK 严格大小写 else: return HttpResponse("主机名太短") # 返回错误提示
3、对前后端交互完善(当后端有问题时,前端收不到data,页面无反应)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<div class="add-modal hide"> <form method="POST" action="/home/"> <div class="group"> <input id='host' type="text" placeholder="主机名" name="hostname" /> </div> <div class="group"> <input id='ip' type="text" placeholder="IP" name="ip" /> </div> <div class="group"> <input id='port' type="text" placeholder="端口" name="port" /> </div> <div class="group"> <select id='sel' name="b_id"> {% for op in b_list %} <option value="{{ op.id }}">{{ op.caption }}</option> {% endfor %} </select> </div> <input type="submit" value="提交" /> <a id="ajax_submit">要上天提交</a> <input id="cancel" type="button" value="取消" /> <span id="error_msg"></span> </form> </div>
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
$(function(){
$('#ajax_submit').click(function () {
$.ajax({
url:"/test_ajax/",
type:"POST",
data:{'hostname':$('#host').val(),'ip':$('#ip').val(),'port':$('#port').val(),'b_id':$('#sel').val()},
success:function (data) {
console.log(data) // data {"data": null, "status": false, "error": "u4e3bu673au540du592au77ed"}
var obj = JSON.parse(data); // 反序列化 把字符串data换成对象obj
// 序列化 JSON.stringify() 把obj转换为字符串
if(obj.status){
location.reload() // 重新加载页面
}else {
$('#error_msg').text(obj.error)
}
}
})
})
})
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
import json def test_ajax(request): ret = {'status':True,'error':None,'data':None} # 返回一个字典 try: h = request.POST.get('hostname') i = request.POST.get('ip') p = request.POST.get('port') b = request.POST.get('b_id') print(h,i,p,b) if h and len(h) > 5: # 主机名长度 print("ok") models.Host.objects.create(hostname=h,ip=i,port=p,b_id=b) else: ret['status'] = False ret['error'] = '主机名太短' except Exception as e: ret['status'] = False ret['error'] = '请求错误' return HttpResponse(json.dumps(ret)) # 对字典进行序列化
4、serialize自动获取表单数据
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<form class="add-form" method="POST" action="/home/"> <div class="group"> <input id='host' type="text" placeholder="主机名" name="hostname" /> </div> <div class="group"> <input id='ip' type="text" placeholder="IP" name="ip" /> </div> <div class="group"> <input id='port' type="text" placeholder="端口" name="port" /> </div> <div class="group"> <select id='sel' name="b_id"> {% for op in b_list %} <option value="{{ op.id }}">{{ op.caption }}</option> {% endfor %} </select> </div> <input type="submit" value="提交" /> <a id="ajax_submit">要上天提交</a> <input id="cancel" type="button" value="取消" /> <span id="error_msg"></span> </form>
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
$.ajax({ url:"/test_ajax/", type:"POST", data:$('.add-form').serialize(), // 获取表单数据提交 必须是form表单 success:function (data) { })
5、Ajax代码补充(traditional,dataType)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
$(function(){
$('#add_submit_ajax').click(function(){
$.ajax({
url: '/ajax_add_app',
data: {'user': 123,'host_list': [1,2,3,4]},
// data: $('#add_form').serialize(),
type: "POST",
dataType: 'JSON', // 内部对传过来的数据直接执行JSON.parse 拿到的数据直接为对象而非字符串
traditional: true, // 添加此项 当字典里包含列表时候,后端可以getlist到里面的数据
success: function(obj){
console.log(obj);
},
error: function () { // 未知错误时执行,指前端收不到后台发送的obj时,执行
}
})
});
})
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
def ajax_add_app(request): ret = {'status':True, 'error':None, 'data': None} app_name = request.POST.get('app_name') host_list = request.POST.getlist('host_list') obj = models.Application.objects.create(name=app_name) obj.r.add(*host_list) return HttpResponse(json.dumps(ret))
6、页面跳转和刷新
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
$.ajax({
url: '/index/',
data: {'k': 'v', 'list': [1,2,3,4], 'k3': JSON.stringfy({'k1': 'v'}))}, $(form对象).serilize()
type: 'POST',
dataType: 'JSON':
traditional: true,
success:function(d){
location.reload() # 刷新
location.href = "某个地址" # 跳转
}
})
二、 Ajax(part2)
原生Ajax、JQuery、伪Ajax三种方式使用优先级:
如果发送的是【普通数据】: jQuery > XMLHttpRequest > iframe
如果发送的是【文件】 : iframe > jQuery(FormData) > XMLHttpRequest(FormData)
①原生Ajax操作
Ajax主要就是使用 【XmlHttpRequest】对象来完成请求的操作,该对象在主流浏览器中均存在(除早起的IE),Ajax首次出现IE5.5中存在(ActiveX控件)
1、XmlHttpRequest对象介绍
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
a. void open(String method,String url,Boolen async)
用于创建请求
参数:
method: 请求方式(字符串类型),如:POST、GET、DELETE...
url: 要请求的地址(字符串类型)
async: 是否异步(布尔类型)
b. void send(String body)
用于发送请求
参数:
body: 要发送的数据(字符串类型)
c. void setRequestHeader(String header,String value)
用于设置请求头
参数:
header: 请求头的key(字符串类型)
vlaue: 请求头的value(字符串类型)
d. String getAllResponseHeaders()
获取所有响应头
返回值:
响应头数据(字符串类型)
e. String getResponseHeader(String header)
获取响应头中指定header的值
参数:
header: 响应头的key(字符串类型)
返回值:
响应头中指定的header对应的值
f. void abort()
终止请求
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
a. Number readyState 状态值(整数) 详细: 0-未初始化,尚未调用open()方法; 1-启动,调用了open()方法,未调用send()方法; 2-发送,已经调用了send()方法,未接收到响应; 3-接收,已经接收到部分响应数据; 4-完成,已经接收到全部响应数据; b. Function onreadystatechange 当readyState的值改变时自动触发执行其对应的函数(回调函数) c. String responseText 服务器返回的数据(字符串类型) d. XmlDocument responseXML 服务器返回的数据(Xml对象) e. Number states 状态码(整数),如:200、404... f. String statesText 状态文本(字符串),如:OK、NotFound...
2、用原生Ajax做个请求
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> </head> <body> <input type="text"/> <input type="button" value="Ajax1" onclick="Ajax1();" /> <script> function Ajax1(){ var xhr = new XMLHttpRequest(); xhr.open('POST', '/ajax_json/',true); xhr.onreadystatechange = function(){ if(xhr.readyState == 4){ // 接收完毕 var obj = JSON.parse(xhr.responseText); console.log(obj); } }; xhr.setRequestHeader('k1','v1'); // post请求必须加下面这句请求头 不然后台数据拿不到 xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset-UTF-8'); xhr.send("name=root;pwd=123"); } </script> </body> </html>
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
def ajax(request): return render(request,'ajax.html') def ajax_json(request): print(request.POST) ret = {'code':True,'data':None} import json return HttpResponse(json.dumps(ret))
3、跨浏览器支持
XmlHttpRequest(IE7+, Firefox, Chrome, Opera, etc.)
ActiveXObject("Microsoft.XMLHTTP")(IE6, IE5)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title></title> </head> <body> <h1>XMLHttpRequest - Ajax请求</h1> <input type="button" onclick="XmlGetRequest();" value="Get发送请求" /> <input type="button" onclick="XmlPostRequest();" value="Post发送请求" /> <script src="/statics/jquery-1.12.4.js"></script> <script type="text/javascript"> function GetXHR(){ var xhr = null; if(XMLHttpRequest){ xhr = new XMLHttpRequest(); }else{ xhr = new ActiveXObject("Microsoft.XMLHTTP"); } return xhr; } function XhrPostRequest(){ var xhr = GetXHR(); // 定义回调函数 xhr.onreadystatechange = function(){ if(xhr.readyState == 4){ // 已经接收到全部响应数据,执行以下操作 var data = xhr.responseText; console.log(data); } }; // 指定连接方式和地址----文件方式 xhr.open('POST', "/test/", true); // 设置请求头 xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset-UTF-8'); // 发送请求 xhr.send('n1=1;n2=2;'); } function XhrGetRequest(){ var xhr = GetXHR(); // 定义回调函数 xhr.onreadystatechange = function(){ if(xhr.readyState == 4){ // 已经接收到全部响应数据,执行以下操作 var data = xhr.responseText; console.log(data); } }; // 指定连接方式和地址----文件方式 xhr.open('get', "/test/", true); // 发送请求 xhr.send(); } </script> </body> </html>
②“伪”AJAX
由于HTML标签的iframe标签具有局部加载内容的特性,所以可以使用其来伪造Ajax请求,进行偷偷的发送请求
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
def ajax(request): return render(request,'ajax.html') def ajax_json(request): print(request.POST) ret = {'code':True,'data':None} import json return HttpResponse(json.dumps(ret))
1.Form表单提交到iframe中,页面不刷新
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> </head> <body> <input type="text"/> <input type="button" value="Ajax1" onclick="Ajax1();" /> <form action="/ajax_json/" method="POST" target="ifm1"> <!-- target跟iframe进行关联 --> <iframe id="ifm1" name="ifm1" ></iframe> <input type="text" name="username" /> <input type="text" name="email" /> <input type="submit" value="Form提交"/> </form> </body> </html>
2.Ajax提交到iframe中,页面不刷新
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> </head> <body> <input type="text"/> <input type="button" value="Ajax1" onclick="Ajax1();" /> <input type='text' id="url" /> <input type="button" value="发送Iframe请求" onclick="iframeRequest();" /> <iframe id="ifm" src="http://www.baidu.com"></iframe> <script src="/static/jquery-1.12.4.js"></script> <script> function iframeRequest(){ var url = $('#url').val(); $('#ifm').attr('src',url); } </script> </body> </html>
3.Form表单提交到iframe中,并拿到iframe中的数据
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> </head> <body> <input type="text"/> <input type="button" value="Ajax1" onclick="Ajax1();" /> <form action="/ajax_json/" method="POST" target="ifm1"> <iframe id="ifm1" name="ifm1" ></iframe> <input type="text" name="username" /> <input type="text" name="email" /> <input type="submit" onclick="sumitForm();" value="Form提交"/> </form> <script type="text/javascript" src="/static/jquery-1.12.4.js"></script> <script> function sumitForm(){ $('#ifm1').load(function(){ var text = $('#ifm1').contents().find('body').text(); var obj = JSON.parse(text); console.log(obj) }) } </script> </body> </html>
三、XmlHttpRequest、JQuery、Iframe进行文件上传
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
def upload(request): return render(request,'upload.html') def upload_file(request): username = request.POST.get(('username')) fafafa = request.FILES.get('fafafa') #获取文件 with open(fafafa.name,'wb') as f: for item in fafafa.chunks(): f.write(item) print(username,fafafa) ret = {'code': True, 'data': request.POST.get('username')} import json return HttpResponse(json.dumps(ret))
① 原生Ajax(XmlHttpRequest)上传文件+定制好看的上传按钮
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> <style> .upload{ display: inline-block;padding: 10px; background-color: brown; position: absolute; top: 0; bottom: 0; right: 0; left: 0; z-index: 90; } .file{ width: 100px;height: 50px;opacity: 0; position: absolute; top: 0; bottom: 0; right: 0; left: 0; z-index: 100; } </style> </head> <body> <div style="position: relative; 100px;height: 50px;"> <input class="file" type="file" id="fafafa" name="afafaf" /> <a class="upload">上传</a> </div> <input type="button" value="提交XHR" onclick="xhrSubmit();" /> <script> function xhrSubmit(){ // $('#fafafa')[0] var file_obj = document.getElementById('fafafa').files[0]; //获取文件对象 var fd = new FormData(); fd.append('username','root'); fd.append('fafafa',file_obj); var xhr = new XMLHttpRequest(); xhr.open('POST', '/upload_file/',true); xhr.onreadystatechange = function(){ if(xhr.readyState == 4){ // 接收完毕 var obj = JSON.parse(xhr.responseText); console.log(obj); } }; xhr.send(fd); } </script> </body> </html>
② JQuery进行文件的上传
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> <style> .upload{ display: inline-block;padding: 10px; background-color: brown; position: absolute; top: 0; bottom: 0; right: 0; left: 0; z-index: 90; } .file{ width: 100px;height: 50px;opacity: 0; position: absolute; top: 0; bottom: 0; right: 0; left: 0; z-index: 100; } </style> </head> <body> <div style="position: relative; 100px;height: 50px;"> <input class="file" type="file" id="fafafa" name="afafaf" /> <a class="upload">上传</a> </div> {# <input type="button" value="提交XHR" onclick="xhrSubmit();" />#} <input type="button" value="提交jQuery" onclick="jqSubmit();" /> <div id="preview"></div> <script src="/static/jquery-1.12.4.js"></script> <script> function jqSubmit(){ // $('#fafafa')[0] var file_obj = document.getElementById('fafafa').files[0]; var fd = new FormData(); fd.append('username','root'); fd.append('fafafa',file_obj); $.ajax({ url: '/upload_file/', type: 'POST', data: fd, processData: false, // tell jQuery not to process the data contentType: false, // tell jQuery not to set contentType success:function(arg,a1,a2){ console.log(arg); console.log(a1); console.log(a2); // Object {readyState: 4, responseText: "{"data": "root", "code": true}", status: 200, statusText: "OK"} } }) } </script> </body> </html>
上面两种方式都用到FormData(),但是如果是IE浏览器的话是不支持FormData(),所以就得用到下面这种方式。
③ Iframe进行文件的上传
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> </head> <body> <form id="form1" action="/upload_file/" method="POST" enctype="multipart/form-data" target="ifm1"> <iframe id="ifm1" name="ifm1" style="display: none;"></iframe> <input type="file" name="fafafa" /> <input type="submit" onclick="iframeSubmit();" value="Form提交"/> </form> <script src="/static/jquery-1.12.4.js"></script> <script> function iframeSubmit(){ $('#ifm1').load(function(){ var text = $('#ifm1').contents().find('body').text(); var obj = JSON.parse(text); console.log(obj) }) } </script> </body> </html>
四、上传文件时图片预览
① 点击上传文件提交
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
def upload(request): return render(request,'upload.html') def upload_file(request): username = request.POST.get(('username')) fafafa = request.FILES.get('fafafa') #获取文件 import os img_path = os.path.join('static/imgs/',fafafa.name) #static下创建imgs目录 with open(img_path,'wb') as f: for item in fafafa.chunks(): f.write(item) print(username,fafafa) ret = {'code': True, 'data': img_path} import json return HttpResponse(json.dumps(ret))
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> </head> <body> <form id="form1" action="/upload_file/" method="POST" enctype="multipart/form-data" target="ifm1"> <iframe id="ifm1" name="ifm1" style="display: none;"></iframe> <input type="file" name="fafafa" /> <input type="submit" onclick="iframeSubmit();" value="Form提交"/> </form> <div id="preview"></div> <script src="/static/jquery-1.12.4.js"></script> <script> function iframeSubmit(){ $('#ifm1').load(function(){ var text = $('#ifm1').contents().find('body').text(); var obj = JSON.parse(text); console.log(obj) $('#preview').empty(); var imgTag = document.createElement('img'); imgTag.src = "/" + obj.data; $('#preview').append(imgTag); }) } </script> </body> </html>
② 选择文件后,直接上传
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> </head> <body> <form id="form1" action="/upload_file/" method="POST" enctype="multipart/form-data" target="ifm1"> <iframe id="ifm1" name="ifm1" style="display: none;"></iframe> <input type="file" name="fafafa" onchange="changeUpalod();" /> //onchange 选中文件时触发 {# <input type="submit" onclick="iframeSubmit();" value="Form提交"/>#} </form> <div id="preview"></div> <script src="/static/jquery-1.12.4.js"></script> <script> function changeUpalod(){ $('#ifm1').load(function(){ //load 绑定load事件,有数据时执行 var text = $('#ifm1').contents().find('body').text(); var obj = JSON.parse(text); $('#preview').empty(); var imgTag = document.createElement('img'); imgTag.src = "/" + obj.data; $('#preview').append(imgTag); }); $('#form1').submit(); } </script> </body> </html>