54-AJAX
1、AJAX准备知识-JSON
1.1 什么是JSON
什么是JSON?JSON全称JavaScript Object Notation(JS对象表示方法)。JSON是轻量级的文本数据交换格式,使用 JavaScript 语法来描述数据对象,但 JSON 仍然独立于语言和平台。
1.2 JSON对象表示
["one", "two", "three"] { "one": 1, "two": 2, "three": 3 } {"names": ["张三", "李四"] } [ { "name": "张三"}, {"name": "李四"} ]
下面的表示方法不正确:
{ name: "张三", 'age': 32 } // 属性名必须使用双引号 [32, 64, 128, 0xFFF] // 不能使用十六进制值 { "name": "张三", "age": undefined } // 不能使用undefined { "name": "张三", "birthday": new Date('Fri, 26 Aug 2011 07:13:10 GMT'), "getName": function() {return this.name;} // 不能使用函数和日期对象 }
1.3 JavaScript序列化和反序列化
序列化:将JavaScript值或对象转换为JSON字符串,使用stringify方法:
JSON.stringify({"name":"Druid"});
反序列化:将JSON对象转换为JavaScript值或对象,使用parse方法:
JSON.parse('{"name":"Druid"}');
1.4 JSON和XML的对比
使用XML表示中国的部分省份:
<?xml version="1.0" encoding="utf-8"?> <country> <name>中国</name> <province> <name>黑龙江</name> <cities> <city>哈尔滨</city> <city>大庆</city> </cities> </province> <province> <name>广东</name> <cities> <city>广州</city> <city>深圳</city> <city>珠海</city> </cities> </province> <province> <name>台湾</name> <cities> <city>台北</city> <city>高雄</city> </cities> </province> <province> <name>新疆</name> <cities> <city>乌鲁木齐</city> </cities> </province> </country>
使用JSON表示中国的部分省份:
{ "name": "中国", "province": [{ "name": "黑龙江", "cities": { "city": ["哈尔滨", "大庆"] } }, { "name": "广东", "cities": { "city": ["广州", "深圳", "珠海"] } }, { "name": "台湾", "cities": { "city": ["台北", "高雄"] } }, { "name": "新疆", "cities": { "city": ["乌鲁木齐"] } }] } JSON格式数据
JSON 简单的语法格式和清晰的层次结构明显要比 XML 容易阅读,并且在数据交换方面,由于 JSON 所使用的字符要比 XML 少得多,可以大大得节约传输数据所占用得带宽。
2、AJAX简介
AJAX全称是Asynchronous Javascript And XML(异步的Javascript和XML)。AJAX是一种在无需重新加载整个网页的情况下,能够更新部分网页的技术,其使用Javascript语言与服务器进行异步交互,传输的数据为XML(当然,传输的数据不只是XML)。AJAX不需要任何浏览器插件,但需要用户允许JavaScript在浏览器上执行。
3、AJAX简单示例
通过AJAX的特性(网页局部刷新)来实现一个网页版简单计算器。
HTML部分:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="x-ua-compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>AJAX局部刷新实例</title> </head> <body> <input type="text" id="i1">+ <input type="text" id="i2">= <input type="text" id="i3"> <input type="button" value="AJAX提交" id="b1"> <script src="/static/jquery-3.2.1.min.js"></script> <script> $("#b1").on("click", function () { $.ajax({ url:"/ajax_add/", type:"GET", data:{"i1":$("#i1").val(),"i2":$("#i2").val()}, success:function (data) { $("#i3").val(data); } {# success中的匿名函数作用为如果发送的请求被后台正确处理,那么则会用匿名函数来处理返回的响应值 #}
}) }) </script> </body> </html>
views.py部分:
def ajax_demo1(request): return render(request, "ajax_demo1.html") def ajax_add(request): i1 = int(request.GET.get("i1")) i2 = int(request.GET.get("i2")) ret = i1 + i2 return JsonResponse(ret, safe=False)
url.py部分:
urlpatterns = [ ... url(r'^ajax_add/', views.ajax_add), url(r'^ajax_demo1/', views.ajax_demo1), ... ]
4、AJAX如何设置CRSF_Token
方法一:通过获取隐藏的input标签中的csrfmiddlewaretoken值,放置在data中发送。
$("#b11").on("click", function () { var csrfToken = $("[name='csrfmiddlewaretoken']").val(); $.ajax({ url: "/ajax_add11/", type: "POST", data: {"i1": $("#i1").val(), "i2": $("#i2").val(), "csrfmiddlewaretoken": csrfToken}, success: function (return_ret) { $("#i3").val(return_ret); } {# success中的匿名函数作用为如果发送的请求被后台正确处理,那么则会用匿名函数来处理返回的响应值 #} }) });
方法二:通过获取返回的cookie中的字符串 放置在请求头中发送。注意:需要引入一个jquery.cookie.js插件。
$.ajax({ url: "/cookie_ajax/", type: "POST", headers: {"X-CSRFToken": $.cookie('csrftoken')}, // 从Cookie取csrftoken,并设置到请求头中 data: {"username": "Q1mi", "password": 123456}, success: function (data) { console.log(data); } })
方法三:自己写方法
function getCookie(name) { var cookieValue = null; if (document.cookie && document.cookie !== '') { var cookies = document.cookie.split(';'); for (var i = 0; i < cookies.length; i++) { var cookie = jQuery.trim(cookies[i]); // Does this cookie string begin with the name we want? if (cookie.substring(0, name.length + 1) === (name + '=')) { cookieValue = decodeURIComponent(cookie.substring(name.length + 1)); break; } } } return cookieValue; } var csrftoken = getCookie('csrftoken');
每一次都这么写太麻烦了,可以使用$.ajaxSetup()方法为ajax请求统一设置。
function csrfSafeMethod(method) { // these HTTP methods do not require CSRF protection return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method)); } $.ajaxSetup({ beforeSend: function (xhr, settings) { if (!csrfSafeMethod(settings.type) && !this.crossDomain) { xhr.setRequestHeader("X-CSRFToken", csrftoken); } } });
注意:
如果使用从cookie中取csrftoken的方式,需要确保cookie存在csrftoken值。
如果你的视图渲染的HTML文件中没有包含 {% csrf_token %},Django可能不会设置CSRFtoken的cookie。
这个时候需要使用ensure_csrf_cookie()装饰器强制设置Cookie。
django.views.decorators.csrf import ensure_csrf_cookie
@ensure_csrf_cookie
def login(request):
pass
5、AJAX上传文件
XMLHttpRequest 是一个浏览器接口,通过它,我们可以使得 Javascript 进行 HTTP (S) 通信。XMLHttpRequest 在现在浏览器中是一种常用的前后台交互数据的方式。2008年 2月,XMLHttpRequest Level 2 草案提出来了,相对于上一代,它有一些新的特性,其中 FormData 就是 XMLHttpRequest Level 2 新增的一个对象,利用它来提交表单、模拟表单提交,当然最大的优势就是可以上传二进制文件。
首先看一下formData的基本用法:FormData对象,可以把所有表单元素的name与value组成一个queryString,提交到后台。只需要把 form 表单作为参数传入 FormData 构造函数即可:
介绍一下如何利用 FormData 来上传文件。
// 上传文件示例 $("#b3").click(function () { var formData = new FormData(); formData.append("csrfmiddlewaretoken", $("[name='csrfmiddlewaretoken']").val()); formData.append("f1", $("#f1")[0].files[0]); $.ajax({ url: "/upload/", type: "POST", processData: false, // 告诉jQuery不要去处理发送的数据 contentType: false, // 告诉jQuery不要去设置Content-Type请求头 data: formData, success:function (data) { console.log(data) } }) })
或者使用
var form = document.getElementById("form1"); var fd = new FormData(form);
这样也可以直接通过ajax 的 send() 方法将 fd 发送到后台。
注意:由于 FormData 是 XMLHttpRequest Level 2 新增的接口,现在 低于IE10 的IE浏览器不支持 FormData。
6、用AJAX实现用户名被使用检查
HTML部分:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>用户名注册检查</title> </head> <body> {% csrf_token %} <p> 用户名: <input type="text" id="i1"> <span id="s1"></span> </p> <script src="/static/jquery-3.3.1.js"></script> <script> var csrfToken = $("[name='csrfmiddlewaretoken']").val(); $("#i1").on("blur", function () { var $i1Ele = $(this); var input_val = $(this).val(); $("#s1").text(""); $.ajax({ url: "/check_name/", type: "POST", traditional: true, data: {"name": input_val, "csrfmiddlewaretoken": csrfToken, }, dataType: "json", {# 收到后台数据会将其作为JSON对象处理,并转换为JS对象(相当于进行JSON.parse()操作) #} success: function (arg) { {#alert(arg.value);#} {#alert(typeof arg.value);#} {# 方法一 #} if (arg.status === 1) { $("#s1").text(arg.value).css("color", "#4cae4c"); } else if (arg.status === 0) { $("#s1").text(arg.value).css("color", "red"); } {# 方法二:先不在input标签后设置span标签,然后人为的增加span标签 #} {# var spanEle = document.createElement("span"); #} {# spanEle.innerText = arg; #} {# $i1Ele.after(spanEle).css("color", "red"); #} } }); }); </script> </body> </html>
views.py部分:
def input_test(request): return render(request, "inputtest.html") def check_name(request): if request.method == "POST": name_str = request.POST.get("name") print(name_str) ret = models.UserInfo.objects.filter(name=name_str) if ret: msg = {"status": 0, "value": "用户名已被占用!"} else: msg = {"status": 1, "value": "用户名可用!"} msg_str = json.dumps(msg) print(msg_str)
urls.py部分:
urlpatterns = [ url(r'^inputhome/', views.input_test), url(r'^check_name/', views.check_name), ]
如果输入的用户名已经存在:
如果输入的用户名不存在:
7、Django内置的序列化方法
def json_test(request): person_ret = models.Person.objects.all() print(person_ret) from django.core import serializers json_ret = serializers.serialize("json", person_ret) return HttpResponse(json_ret)
8、AJAX其它操作
8.1 重定向操作
HTML部分:
<body> <input type="button" value="AJAX跳转" id="b2" /> <script> $("#b2").on("click", function () { $.ajax({ url: "/redirect/" , type: "GET", success: function (page) { location.href = page; {# JS用来重定向的语法 #} } }) }); </script> </body>
views.py部分:
def redirect(request): url = "https://www.baidu.com" return HttpResponse(url)
urls.py部分:
urlpatterns = [ url(r'^index/', views.index), url(r'^redirect/', views.redirect), ]
8.2 插入图片
HTML部分:
<body> <input type="button" value="新垣结衣" id="b3" /> <script> $("#b3").on("click", function () { $.ajax({ url: "/img/", type: "GET", success: function (img_src) { var imgEle = document.createElement("img"); imgEle.src = img_src; $("#b3").after(imgEle); } }) }); </script> </body>
views.py部分:
def img(request): import time url = "https://img04.sogoucdn.com/app/a/100520093/20c4810dc183baae-5def1b18ddcc085b-f8e0d862ee45cf40a899c001398d6a3b.jpg" return HttpResponse(url)
urls.py部分:
urlpatterns = [ url(r'^index/', views.index), url(r'^img/', views.img), ]
9、sweetalert插件示例
HTML部分:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <link rel="stylesheet" href="/static/bootstrap/css/bootstrap.min.css"> <link rel="stylesheet" href="/static/fontawesome/css/font-awesome.min.css"> <link rel="stylesheet" href="/static/sweetalert/sweetalert.css"> <style> .sweet-alert > h2 { padding-top: 10px; } </style> </head> <body> {% csrf_token %} <div class="container"> <div class="panel panel-default"> <div class="panel-heading"> <h3 class="panel-title">人员管理</h3> </div> <div class="panel-body"> <table class="table table-bordered"> <thead> <tr> <th>序号</th> <th>ID</th> <th>姓名</th> <th>年龄</th> <th>生日</th> <th>操作</th> </tr> </thead> <tbody> {% for person in persons %} <tr> <td>{{ forloop.counter }}</td> <td>{{ person.id }}</td> <td>{{ person.name }}</td> <td>{{ person.age }}</td> <td>{{ person.birthday|date:'Y-m-d' }}</td> <td> <button class="btn btn-danger del"> <i class="fa fa-trash-o">删除</i> </button> </td> </tr> {% endfor %} </tbody> </table> </div> </div> <script src="/static/jquery-3.3.1.js"></script> <script src="/static/bootstrap/js/bootstrap.min.js"></script> <script src="/static/sweetalert/sweetalert.min.js"></script> <script> var csrfToken = $("[name='csrfmiddlewaretoken']").val(); $(".del").on("click", function () { var $TrElm = $(this).parent().parent(); {# 获取要删除行的tr$对象 #} var delId = $TrElm.children().eq(1).text(); {# 获取要删除数据的ID #} swal({ title: "确认要删除吗?", text: "删除后将不可恢复!", type: "warning", showCancelButton: true, confirmButtonClass: "btn-danger", cancelButtonText: "取消", confirmButtonText: "确认", closeOnConfirm: false }, function () { $.ajax({ url: "/delete/", type: "POST", data: {"id": delId, "csrfmiddlewaretoken": csrfToken}, success: function (arg) { swal(arg, "数据删除已完成", "success"); $TrElm.remove(); {# 删除该行tr #} } }); }); }) </script> </div> </body> </html>
views.py部分:
def sweet_alert(request): person_obj = models.Person.objects.all() return render(request, "sweetalertdemo.html", {"persons": person_obj})
urls.py部分:
urlpatterns = [ url(r'^sweetalert/', views.sweet_alert), ]
最终页面效果: