Ajax的原理及Django上传组件
Ajax的原理
ajax 是异步JavaScript和xml
ajax就是向后台提交数据但是不刷新页面
原生Ajax XMLHttprequest
- 创建一个XMLHttprequest对象
- 回调函数onreadystatechange 对应jQuery中的success
- 状态值是不断变化的,4代表完成,已经接收到全部响应数据;
- open是创建请求
- send是发送数据
XMLHttprequest对象的主要方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| 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() 终止请求
|
XMLHttprequest的主要属性
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| 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..
|
GET 请求
下面是通过GTE在URL中发用的数据
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| <input type="button" id="btn2" value="原生 Ajax" onclick="add2();"> <script> function add2() { var xhr = new XMLHttpRequest(); //创建一个XMLHttpRequest对象 xhr.onreadystatechange = function () { //回调函数 状态值是4的时候代表数据返回成功 if(xhr.readyState==4){ alert(xhr.responseText); // 服务器返回的数据 } }; xhr.open('GET','/add2/?i1=1&i2=3'); // 第一个参数是method 第二个是URL 第三个是默认异步 xhr.send(); } </script>
|
1 2 3 4 5 6
| def add2(request): if request.method == "GET": i1 =int(request.GET.get('i1')) i2 =int(request.GET.get('i2')) print('add2') return HttpResponse(i1+i2)
|
POST请求
POST请求的内容需要放到请求体中发送,而且需要设置请求头
1 没有设置请求头的情况
1 2 3 4 5 6 7 8 9 10 11 12 13
| <script> function add2() { var xhr = new XMLHttpRequest(); //创建一个XMLHttpRequest对象 xhr.onreadystatechange = function () { //回调函数 状态码是4的时候代表数据返回成功 if(xhr.readyState==4){ alert(xhr.responseText); // 服务器返回的数据 } }; xhr.open('POST','/add2/'); // 第一个参数是method 第二个是URL 第三个是默认异步(不用写) xhr.send('i1=1&i2=3'); //发送的内容放到请求体中 } </script>
|
在后台从request.POST中获取不到数据,数据存在request.body中
1 2 3 4 5 6 7 8 9 10
| def add2(request): if request.method == "GET": i1 =int(request.GET.get('i1')) i2 =int(request.GET.get('i2')) print('add2') return HttpResponse(i1+i2) else: print(request.POST) print(request.body) return HttpResponse("...")
|
结果:
1 2
| <QueryDict: {}> post中没有数据 b'i1=1&i2=3' body总的数据
|
2 设置请求头
- xhr.setRequestHeader(‘Content-Type’,’application/x-www-form-urlencoded’);
1 2 3 4 5 6 7 8 9 10
| var xhr = new XMLHttpRequest(); //创建一个XMLHttpRequest对象 xhr.onreadystatechange = function () { //回调函数 状态码是4的时候代表数据返回成功 if(xhr.readyState==4){ alert(xhr.responseText); // 服务器返回的数据 } }; xhr.open('POST','/add2/'); // 第一个参数是method 第二个是URL 第三个是默认异步 xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded'); //添加请求头 xhr.send('i1=1&i2=3');
|
jQueryAjax
jQuery本身是没有ajax的,是封装了原生的ajax
使用jQuery的ajax的计算器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| <input type="text" id="i1"> + <input type="text" id="i2"> = <input type="text" id="i3"> <input type="button" id="btn1" value="jQuery Ajax" onclick="add1();"> <script src="/static/jquery-1.12.4.js"></script> <script> function add1() { $.ajax({ url:'/add1/', type:'POST', data:{ 'i1':$('#i1').val(), 'i2':$('#i2').val(), }, success:function (arg) { $('#i3').val(arg) } }) } </script>
|
1 2 3 4
| def add1(request): a1 = int(request.POST.get('i1')) a2 = int(request.POST.get('i2')) return HttpResponse(a1+a2)
|
伪Ajax,非XMLHttprequest
iframe标签具有不刷新打开页面的功能
结合Form发送,form设置成通过iframe进行发送数据。
关键点是target
1 iframe的应用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <div> <input type="text" id="tex1"> <input type="button" value="查看" onclick="changeScr();"> </div> <iframe id="ifr" style="width: 1000px;height: 2000px" src="https://www.baidu.com"></iframe> <script> function changeScr() { var inp = document.getElementById('tex1').value; //value 获取文本中的内容 document.getElementById('ifr').src=inp; // 找到iframe标签并设置src属性 } </script> </body> </html>
|
2 iframe结合form
target是iframe 的name属性的名字,这样form就会通过iframe进行发送
1 2 3 4 5
| <form action="/fake_ajax/" method="POST" id="f1" target="ifrname"> <iframe name="ifrname" id="ifr" ></iframe> <input type="text" name="user"> <input type="submit"> </form>
|
3 伪ajax的回调函数
使用onload,在iframe加载完后就代表数据发送回来了
- 把iframe的样式隐藏display none
- 使用js提交表单,否则onload会是未定义
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| <form action="/fake_ajax/" method="POST" id="f1" target="ifrname"> <iframe name="ifrname" id="ifr" style="display: none"></iframe> <input type="text" name="user"> <a onclick="submitForm();">提交</a> </form> <script> function submitForm() { document.getElementById('ifr').onload = loadIframe; // 绑定事件后执行函数 document.getElementById('f1').submit(); //js提交表单 } //回调函数 function loadIframe() { alert(123); {# var content = document.getElementById('ifr').contentWindow.document.body.innerText;#} {# alert(content);#} } </script>
|
4 获取iframe中的内容
iframe 实际是在当前页面嵌套了一个页面,存放在body中。
要进入,就要获取这个对象。用contentWindow,进入iframe的对象
1 2 3 4 5 6 7 8 9 10 11
| <script> function submitForm() { document.getElementById('ifr').onload = loadIframe; document.getElementById('f1').submit(); } function loadIframe() { var content = document.getElementById('ifr').contentWindow.document.body.innerText; alert(content); } </script>
|
Ajax上传文件
上面通过XMLHttpresquest发送的是字符串,下面发送的是文件,具体说是文件对象,包含发送的文件的信息。
XMLHttpresquest
利用XMLHttpresquest发送数据,还需要一个formData对象,
用 formData.append('k1','v1');添加发送的数据
原生
1 用formdata发送字符串
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h1>原生ajax上传文件</h1> <a onclick="upload1();">上传</a> <script src="/static/jquery-1.12.4.js"></script> <script> function upload1() { var formData = new FormData(); formData.append('k1','v1'); var xhr = new XMLHttpRequest(); xhr.onreadystatechange = function () { if(xhr.readyState==4){ alert(xhr.responseText) } }; xhr.open('POST','/upload/'); xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded'); xhr.send(formData); }; </script> </body> </html>
|
后台获取的数据:
1 2 3 4 5 6
| def upload(request): if request.method == "GET": return render(request, 'upload.html') else: print(request.POST) return HttpResponse('...')
|
结果:
1
| <QueryDict: {'------WebKitFormBoundaryyPbfiKT1zk4kFYTP\r\nContent-Disposition: form-data': [''], ' name': ['"k1"\r\n\r\nv1\r\n------WebKitFormBoundaryyPbfiKT1zk4kFYTP--\r\n']}>
|
1.1 formdata对象发送字符串
上面的情况是加上了请求头,这是自己用原生的XMLHttpresponse发送数据的时候
而formdata能够自动处理发送的数据(字符串、文件)
formdata发送字符串在后台直接获取
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h1>原生ajax上传文件</h1> <a onclick="upload1();">上传</a> <script src="/static/jquery-1.12.4.js"></script> <script> function upload1() { var formData = new FormData(); formData.append('k1','v1'); var xhr = new XMLHttpRequest(); xhr.onreadystatechange = function () { if(xhr.readyState==4){ alert(xhr.responseText) } }; xhr.open('POST','/upload/'); xhr.send(formData); }; </script> </body> </html>
|
后台获取的数据:
1
| <QueryDict: {'k1': ['v1']}>
|
2 formdata对象发送文件

- 创建FormData对象
- 添加要发送的文件对象的,是一个列表,包含文件的信息
document.getElementById('i1').files[0]
- send(formdata) 最后发送的是formdata对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h1>原生ajax上传文件</h1> <input type="file" id="i1"> <a onclick="upload1();">上传</a> <script src="/static/jquery-1.12.4.js"></script> <script> function upload1() { var formData = new FormData(); formData.append('k1','v1'); formData.append('upload_file',document.getElementById('i1').files[0]); var xhr = new XMLHttpRequest(); xhr.onreadystatechange = function () { if(xhr.readyState==4){ var file_path = xhr.responseText; alert(file_path) } }; xhr.open('POST','/upload/'); xhr.send(formData); } </script> </body> </html>
|
后台
- 获取文件对象file_obj,
request.FILES.get('upload_file'),文件名和前端对应
- 这个文件对象打印出来的是文件的名字
- 文件对象中chunks()是存在内存中的。保存文件要从内存保存到本地
- 拼接文件路径
- 把文件的路径返回到前端
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| def upload(request): if request.method == "GET": return render(request, 'upload.html') else: print(request.POST) print(request.FILES) file_obj = request.FILES.get('upload_file') print(file_obj) print("...") print(file_obj.chunks()) file_path = os.path.join('static', file_obj.name) print(file_path) with open(file_path, 'wb') as f: """ 打开文件 模式:wb 写入 一点点打开文件并写入 """ for chunk in file_obj.chunks(): f.write(chunk) return HttpResponse(file_path)
|
3 ajax上传图片并预览
- 返回上传文件的路径
- 路径加 / + file_path 进行拼接
- 动态创建img 添加src
- 找到div appendchild
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h1>原生ajax上传文件</h1> <input type="file" id="i1"> <a onclick="upload1();">上传</a> <div id="container1"> </div> <script src="/static/jquery-1.12.4.js"></script> <script> function upload1() { var formData = new FormData(); formData.append('k1','v1'); formData.append('upload_file',document.getElementById('i1').files[0]); var xhr = new XMLHttpRequest(); xhr.onreadystatechange = function () { if(xhr.readyState==4){ var file_path = xhr.responseText; alert(file_path); var tag = document.createElement('img'); tag.src ='/'+ file_path; document.getElementById('container1').appendChild(tag); } }; xhr.open('POST','/upload/'); xhr.send(formData); } </script> </body> </html>
|
使用jQuery
jQuery内部也是用的XMLHttpresquest,也是用formdata,还需要告知jQuery不在请求头添加内容
contentType:false,processData:false,
否则遇到的错误是:Uncaught TypeError: Illegal invocation
DOM 对象和jQuery对象的转换
1 2
| jQuery -> DOM :$('#i2')[0] # 取0就是第一个元素 DOM -> jQuery : $(document.getElementById('i2')) #直接加$
|
http://www.cnblogs.com/Python666/p/6925517.html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h1>jQuery ajax上传文件</h1> <input type="file" id="i2"> <a onclick="upload2();">上传</a> <div id="container2"></div> <script src="/static/jquery-1.12.4.js"></script> <script> function upload2() { var formData = new FormData(); //用一个FormData对象发送 formData.append('k1','v1'); {# formData.append('upload_file',document.getElementById('i2').files[0]);#} formData.append('upload_file',$('#i2')[0].files[0]); // 使用jQuery获取文件对象 /* DOM 对象和jQuery对象的转换 DOM -> jQuery :$('#i2')[0] jQuery -> DOM : $(document.getElementById('i2')) */ $.ajax({ url:'/upload/', type:'POST', data:formData, contentType:false, processData:false, success:function (arg) { alert(arg); var tag = document.createElement('img'); // 动态创建img标签 tag.src ='/'+ arg; // 返回值args就是文件路径 静态文件路径的开头有 斜杠 {#document.getElementById('container2').appendChild(tag); // 把img 添加到container1#} $('#container2').append(tag); //使用js动态添加 } }) } </script> </body> </html>
|
伪Ajax
伪Ajax上传的兼容性好,form上传的参数enctype="multipart/form-data"
- 设置input标签的name为upload_file,后台获取name属性名-> 获取文件对象
- XMLHttprequest 是通过formData append中 与后台的获取文件对象的名字一致
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h1>伪ajax上传文件</h1> <form id="f1" method="POST" action="/upload/" target="ifr" enctype="multipart/form-data"> <iframe id="ifr" name="ifr" style="display: none;"></iframe> <input type="file" name="upload_file"> {# 后台获取name 获取文件对象 #} <a onclick="upload3()">伪ajax上传</a> </form> <div id="container3"></div> <script src="/static/jquery-1.12.4.js"></script> <script> function upload3() { document.getElementById('ifr').onload = loadFrame; document.getElementById('f1').submit();//form通过js进行提交 } function loadFrame() { var content = document.getElementById('ifr').contentWindow.document.body.innerText; {#alert(content);// 返回的是文件的路径#} var tag = document.createElement('img'); tag.src = '/' + content; $('#container3').append(tag); } </script> </body> </html>
|
好看的上传按钮,通常是把原来的input加上了透明度opacity=0,设置zindex,
在下面的一层加上好看的按钮 zindex的值小于input的
参考:
http://www.cnblogs.com/wupeiqi/articles/5703697.html