vlambda博客
学习文章列表

Ajax基本使用、基于Ajax请求的二次删除确认

不知名菜鸟
爱分享,爱生活,爱工作。
64篇原创内容
Official Account


介绍

异步提交,局部刷新。

Ajax基本使用、基于Ajax请求的二次删除确认

合格的json对象(json只认双引的字符串格式):

1["one""two""three"]
2"one"1"two"2"three"3 }
3{"names": ["张三""李四"] }
4[ { "name""张三"}, {"name""李四"} ] 

不合格的json对象:

1{ name: "张三"'age'32 }  // 属性名必须使用双引号
2[32641280xFFF] // 不能使用十六进制值
3"name""张三""age": undefined }  // 不能使用undefined
4"name""张三",
5  "birthday": new Date('Fri, 26 Aug 2011 07:13:10 GMT'),
6  "getName":  function() {return this.name;}  // 不能使用函数和日期对象
7}

AJAX(Asynchronous Javascript And XML)翻译成中文就是“异步的Javascript和XML”。即使用Javascript语言与服务器进行异步交互,传输的数据为XML(当然,传输的数据不只是XML)。

AJAX 不是新的编程语言,而是一种使用现有标准的新方法。

AJAX 最大的优点是在不重新加载整个页面的情况下,可以与服务器交换数据并更新部分网页内容。(这一特点给用户的感受是在不知不觉中完成请求和响应过程)。

AJAX 不需要任何浏览器插件,但需要用户允许JavaScript在浏览器上执行。

  • 同步交互:客户端发出一个请求后,需要等待服务器响应结束后,才能发出第二个请求;

  • 异步交互:客户端发出一个请求后,无需等待服务器响应结束,就可以发出第二个请求。

 1"""
2异步提交
3局部刷新
4例子:github注册
5    动态获取用户名实时的跟后端确认并实时展示的前端(局部刷新)
6
7朝发送请求的方式
8    1.浏览器地址栏直接输入url回车                          GET请求
9    2.a标签href属性                                             GET请求
10    3.form表单                                                         GET请求/POST请求
11    4.ajax                                                              GET请求/POST请求    
12
13AJAX 不是新的编程语言,而是一种使用现有标准的新方法(比较装饰器)
14
15
16AJAX 最大的优点是在不重新加载整个页面的情况下,可以与服务器交换数据并更新部分网页内容。(这一特点给用户的感受是在不知不觉中完成请求和响应过程)
17
18
19Ajax我们只学习jQuery封装之后的版本(不学原生的 原生的复杂并且在实际项目中也一般不用)
20所以我们在前端页面使用ajax的时候需要确保导入了jQuery
21ps:并不只有jQuery能够实现ajax,其他的框架也可以 但是换汤不换药 原理是一样的
22"""


Ajax常见应用场景

搜索引擎根据用户输入的关键字,自动提示检索关键字。

还有一个很重要的应用场景就是注册时候的用户名的查重。

其实这里就使用了Ajax技术!当文件框发生了输入变化时,使用Ajax技术向服务器发送一个请求,然后服务器会把查询到的结果响应给浏览器,最后再把后端返回的结果展示出来。

  • 整个过程中页面没有刷新,只是刷新页面中的局部位置而已!

  • 当请求发出后,浏览器还可以进行其他操作,无需等待服务器的响应!

Ajax基本使用、基于Ajax请求的二次删除确认


jQuery实现Ajax

ajax基本语法
 1# ajax基本语法
2$.ajax({
3  url:'',  # 朝后端哪个地址发送 跟action三种书写方式一致
4  type:'get/post',  # 提交方式 默认get 跟form表单method参数一致
5  data:{'username':'zhangsan','password':123},  # 要发送的数据
6  success:function(args){
7    # 异步回调处理机制
8  } 
9})
10"""
11当你在利用ajax进行前后端交互的时候
12后端无论返回什么都只会被回调函数接受 而不再影响这个浏览器页面了
13"""

14
15# 扩展 参数  代码发布项目还会涉及
16dataType:'JSON'
17"""
18当后端是以HttpResponse返回的json格式的数据
19默认是不会自动反序列化的
20    1.自己手动JSON.parse()
21    2.配置dataType参数
22"""

23
24# 结论:写ajax的时候 你可以直接将dataType参数加上 以防万一 或者后端就用JsonResonse
25$.ajax({
26  url:'',  # 朝后端哪个地址发送 跟action三种书写方式一致
27  type:'get/post',  # 提交方式 默认get 跟form表单method参数一致
28  dataType:'JSON',   # 数据格式定义为JSON格式
29  data:{'username':'zhangsan','password':123},  # 要发送的数据
30  success:function(args){
31    # 异步回调处理机制
32  } 
33})

$.ajax参数

data参数中的键值对,如果值值不为字符串,需要将其转换成字符串类型。

 1$("#b1").on("click"function () {
2    $.ajax({
3      url:"/ajax_add/",
4      type:"GET",
5      data:{"i1":$("#i1").val(),"i2":$("#i2").val(),"hehe"JSON.stringify([123])},
6      success:function (data{
7        $("#i3").val(data);
8      }
9    })
10  })
templates
 1<!DOCTYPE html>
2<html lang="en">
3<head>
4    <meta charset="UTF-8">
5    <title>Title</title>
6    <meta name="viewport" content="width=device-width, initial-scale=1">
7
8    <style>
9        .hide {
10            display: none;
11        }
12    </style>

13</head>
14<body>
15<p><input type="text" class="user"><span class="hide" style="color: red">用户名已存在</span></p>
16
17<script src="/static/jquery-3.3.1.min.js"></script>
18{#下面这一项是基于jQuery的基础上自动给我们的每一个ajax绑定一个请求头信息,类似于form表单提交post数据必须要有的csrf_token一样#}
19{#否则我的Django中间件里面的校验csrf_token那一项会认为你这个请求不是合法的,阻止你的请求#}
20<script src="/static/setup_Ajax.js"></script>
21<script>
22    //给input框绑定一个失去焦点的事件
23    $('.user').blur(function () {
24        //$.ajax为固定用法,表示启用ajax
25        $.ajax({
26            //url后面跟的是你这个ajax提交数据的路径,向谁提交,不写就是向当前路径提交
27            url:'',
28            //type为标定你这个ajax请求的方法
29            type:'POST',
30            //data后面跟的就是你提交给后端的数据
31            data:{'username':$(this).val()},
32            //success为回调函数,参数data即后端给你返回的数据
33            success:function (data{
34                ret=JSON.parse(data);
35                if (ret['flag']){
36                    $('p>span').removeClass('hide');
37                }
38            }
39        })
40    });
41</script>

42</body>
43</html>
views.py
 1from 
2
3def index(request):
4    if request.method=='POST':
5        ret={'flag':False}
6        username=request.POST.get('username')
7        if username=='JBY':
8            ret['flag']=True
9            import json
10            return HttpResponse(json.dumps(ret))
11    return render(request,'index.html')


案例

 1"""
2页面上有三个input框
3    在前两个框中输入数字 点击按钮 朝后端发送ajax请求
4    后端计算出结果 再返回给前端动态展示的到第三个input框中
5    (整个过程页面不准有刷新,也不能在前端计算)
6"""

7$('#btn').click(function () {
8        // 朝后端发送ajax请求
9        $.ajax({
10            // 1.指定朝哪个后端发送ajax请求
11            url:'', // 不写就是朝当前地址提交
12            // 2.请求方式
13            type:'post',  // 不指定默认就是get 都是小写
14            // 3.数据
15            {#data:{'username':'jason','password':123},#}
16            data:{'i1':$('#d1').val(),'i2':$('#d2').val()},
17            // 4.回调函数:当后端给你返回结果的时候会自动触发 args接受后端的返回结果
18            success:function (args) {
19                {#alert(args)  // 通过DOM操作动态渲染到第三个input里面#}
20                {#$('#d3').val(args)#}
21                console.log(typeof args)
22
23            }
24        })
25    })
26
27
28"""
29针对后端如果是用HttpResponse返回的数据 回调函数不会自动帮你反序列化
30如果后端直接用的是JsonResponse返回的数据 回调函数会自动帮你反序列化
31
32HttpResponse解决方式
33    1.自己在前端利用JSON.parse()
34    2.在ajax里面配置一个参数
35"""


前后端传输数据的编码格式(contentType)

 1# 我们主要研究post请求数据的编码格式
2"""
3get请求数据就是直接放在url后面的
4url?username=jason&password=123
5"""

6
7# 可以朝后端发送post请求的方式
8    """
9    1.form表单
10    2.ajax请求
11    """


1"""
2前后端传输数据的编码格式
3    urlencoded
4
5    formdata
6
7    json
8"""


研究form表单
 1<!DOCTYPE html>
2<html lang="en">
3<head>
4    <meta charset="UTF-8">
5    <title>Title</title>
6    <meta name="viewport" content="width=device-width, initial-scale=1">
7    {% load static %}
8    <link rel="stylesheet" href="{% static 'bootstrap-3.4.1-dist/css/bootstrap.min.css' %}">
9    <script src="{% static 'jQuery/jquery-3.6.0.min.js' %}"></script>
10    <script src="{% static 'bootstrap-3.4.1-dist/js/bootstrap.min.js' %}"></script>
11</head>
12<body>
13<form action="" method="post">
14    <p>username: <input type="text" name="username" class="form-control"></p>
15    <p>password: <input type="password" name="password" class="form-control"></p>
16    <input type="submit" class="btn btn-success">
17</form>
18</body>
19</html>


动态解析

1STATIC_URL = '/static/'
2STATICFILES_DIRS = [
3    os.path.join(BASE_DIR, 'static')
4]
  • 默认的编码格式

1# urlrencoded

Ajax基本使用、基于Ajax请求的二次删除确认


  • 数据格式

1"""
2username=jack&password=123
3"""

Ajax基本使用、基于Ajax请求的二次删除确认


django后端针对符合urlencoded编码格式的数据都会自动帮你解析封装到request.POST中,即:

1username=jack&password=123    >>> request.POST

1"""
2如果你把编码格式改成formdata,那么针对普通的键值对还是解析到request.POST中,
3而将文件解析到request.FILES中
4
5form表单是没有办法发送json格式数据的
6"""


研究Ajax
1# 研究ajax
2默认的编码格式也是urlencoded
3数据格式:username=jack&age=20
4    django后端针对符合urlencoded编码格式的数据都会自动帮你解析封装到request.POST中
5    username=jack&age=20    >>> request.POST

Ajax基本使用、基于Ajax请求的二次删除确认


1[27/May/2021 21:09:17"POST /index/ HTTP/1.1" 200 1030
2<QueryDict: {'username': ['jack'], 'age': ['20']}>
3<MultiValueDict: {}>

 1<!DOCTYPE html>
2<html lang="en">
3<head>
4    <meta charset="UTF-8">
5    <title>Title</title>
6    <meta name="viewport" content="width=device-width, initial-scale=1">
7    {% load static %}
8    <link rel="stylesheet" href="{% static 'bootstrap-3.4.1-dist/css/bootstrap.min.css' %}">
9    <script src="{% static 'jQuery/jquery-3.6.0.min.js' %}"></script>
10    <script src="{% static 'bootstrap-3.4.1-dist/js/bootstrap.min.js' %}"></script>
11</head>
12<body>
13<form action="" method="post">
14    <p>username: <input type="text" name="username" class="form-control"></p>
15    <p>password: <input type="password" name="password" class="form-control"></p>
16    <input type="submit" class="btn btn-success">
17    <input type="button" class="btn btn-danger" value="按钮" id="d1">
18</form>
19
20<script>
21    $('#d1').click(function () {
22        $.ajax(
23            {
24                url:'',
25                type:'post',
26                data:{'username':'jack''age':20},
27                success:function (args{
28
29                }
30            }
31        )
32    })
33
34</script>

35</body>
36</html>


Ajax发送json格式数据

前后端传输数据的时候一定要确保编码格式数据真正的格式是一致的。

前端编码格式  <==> 后端编码格式。

前端数据转json格式方法:JSON.stringify()

 1<script>
2    $('#d1').click(function () {
3        $.ajax({
4            url:'',
5            type:'post',
6            data:JSON.stringify({'username':'jack','age':18}), // 将数据转成json格式 JSON.stringify()函数方法
7            contentType:'application/json',  // 指定编码格式
8            success:function (args{
9
10            }
11        })
12    })
13</script>

Ajax基本使用、基于Ajax请求的二次删除确认


json格式的数据

Ajax基本使用、基于Ajax请求的二次删除确认


request方法补充
1"""
2request对象方法补充
3    request.is_ajax()
4        判断当前请求是否是ajax请求 返回布尔值
5"""


前后端ajax发送的json数据处理方法
 1import json
2def about_json(request):
3    if request.is_ajax(): # True
4        print(request.is_ajax())
5        # print(request.is_ajax())
6        # print(request.POST)
7        # print(request.FILES)
8        # print(request.body)  # b'{"username":"jack","password":123}'  bytes格式
9        # 针对json格式数据需要你自己手动处理
10        json_bytes = request.body
11        # json_str = json_bytes.decode('utf-8')  # 先解码
12        # json_dict = json.loads(json_str)  # 再进行反序列化
13
14        # json.loads括号内如果传入了一个二进制格式的数据那么内部自动解码再反序列化
15        # 进行反序列化操作
16        json_dict = json.loads(json_bytes)  # {'username': 'jack', 'password': 123} <class 'dict'>
17        print(json_dict, type(json_dict))  
18
19    return render(request, 'about_json.html')

 1<button class="btn btn-danger" id="d1">点我</button>
2
3<script>
4    $('#d1').click(function () {
5        $.ajax({
6            url:'',
7            type:'post',
8            data:JSON.stringify({'username':'jack''password':123}),
9            contentType:'application/json',
10            success:function () {
11
12            }
13
14        })
15    })
16</script>


1"""
2ajax发送json格式数据需要注意:
3    1.contentType参数指定成:application/json
4    2.数据是真正的json格式数据
5    3.django后端不会帮你处理json格式数据需要你自己去request.body获取并处理
6"""


Ajax发送文件数据

ajax发送文件需要借助于js内置对象FormData。

views.py
1def about_file(request):
2    if request.is_ajax():
3        if request.method == 'POST':
4            print(request.POST)
5            # <QueryDict: {'username': ['zhangsan'], 'password': ['888qwee']}>
6            print(request.FILES)
7            # <MultiValueDict: {'file_obj': [<InMemoryUploadedFile: lab2.png (image/png)>]}>
8
9    return render(request, 'about_file.html')
templates
 1<p>username:<input type="text" id="d1"></p>
2<p>password<input type="text" id="d2"></p>
3<p><input type="file" id="d3"></p>
4<button class="btn btn-info" id="d4">点我</button>
5
6<script>
7    // 点击按钮后朝后端发送普通键值对何文件数据
8    $('#d4').click(function () {
9        // 1-先利用formData内置对象
10        let formData_obj = new FormData();
11        // 2-添加普通的键值对
12        formData_obj.append('username', $('#d1').val());
13        formData_obj.append('password', $('#d2').val());
14
15        // 3-添加文件对象
16        formData_obj.append('file_obj', $('#d3')[0].files[0])
17
18        // 4-将对象基于ajax发送至后端
19        $.ajax({
20            url:'',
21            type:'post',
22            data:formData_obj,  // 直接将产生的对象放在这个参数位置
23
24            // ajax发送文件必须要指定的两个参数
25            contentType:false,  // 不需使用任何编码 django后端能够自动识别formdata对象
26            processData:false,  // 告诉你的浏览器不要对你的数据进行任何处理
27
28            success:function (args{
29
30            }
31        })
32    })
33
34</script>

要点总结
 1"""
2总结:
3    1.需要利用内置对象FormData
4                // 2 添加普通的键值对
5                formDateObj.append('username',$('#d1').val());
6                formDateObj.append('password',$('#d2').val());
7                // 3 添加文件对象
8                formDateObj.append('myfile',$('#d3')[0].files[0])
9
10    2.需要指定两个关键性的参数
11                contentType:false,  // 不需使用任何编码 django后端能够自动识别formdata对象
12                processData:false,  // 告诉你的浏览器不要对你的数据进行任何处理
13
14    3.django后端能够直接识别到formdata对象并且能够将内部的普通键值自动解析并封装到request.POST
15                文件数据自动解析并封装到request.FILES中
16"""


django自带的序列化组件

需求:在前端给我获取到后端用户表里面所有的数据 并且要是列表套字典。

1"""
2- 前后端分离的项目
3    - 作为后端开发的你只需要写代码将数据处理好
4    - 能够序列化返回给前端即可 
5        - 再写一个接口文档 告诉前端每个字段代表的意思即可
6
7"""


 1from django.shortcuts import render,  HttpResponse, redirect
2from app01 import models
3from django.http import JsonResponse
4from django.core import serializers
5
6def about_ser(request):
7    user_queryset = models.User.objects.all()
8
9    # 方法1
10    user_list = []
11    for user_obj in user_queryset:
12        tmp = {
13            'pk':user_obj.pk,
14            'username':user_obj.username,
15            'age':user_obj.age,
16            'gender':user_obj.get_gender_display()  # 展示数据内容  而不是数字
17        }
18        user_list.append(tmp)
19    return JsonResponse(user_list, safe=False)
20    """
21        [{"pk": 1, "username": "zhangsan", "age": 123, "gender": "male"},
22         {"pk": 2, "username": "lisi", "age": 22, "gender": "female"}, 
23         {"pk": 3, "username": "mali", "age": 16, "gender": "others"}, 
24         {"pk": 4, "username": "tony", "age": 55, "gender": 4}]
25
26    """

27
28    # 方法2
29    # 序列化
30    res = serializers.serialize('json', user_queryset)
31    """会自动帮你将数据变成json格式的字符串 并且内部非常的全面"""
32    return HttpResponse(res)
33
34    """
35    [
36    {"model": "app01.user", 
37        "pk": 1, 
38        "fields": {"username": "zhangsan", "age": 123, "gender": 1}}, 
39    {"model": "app01.user", 
40        "pk": 2,
41         "fields": {"username": "lisi", "age": 22, "gender": 2}}, 
42    {"model": "app01.user", 
43        "pk": 3, 
44        "fields": {"username": "mali", "age": 16, "gender": 3}}, 
45    {"model": "app01.user", 
46        "pk": 4, 
47        "fields": {"username": "tony", "age": 55, "gender": 4}}
48    ]
49
50    写接口就是利用序列化组件渲染数据然后写一个接口文档 该交代交代一下就完事
51    """



案例

Ajax结合sweetaler实现删除按钮的二次确认

1"""
2自己要学会如何拷贝
3学会基于别人的基础之上做修改
4研究各个参数表示的意思 然后找葫芦画瓢
5"""

sweetalert源代码

 1swal({
2  title"Are you sure?",
3  text"You will not be able to recover this imaginary file!",
4  type"warning",
5  showCancelButtontrue,
6  confirmButtonClass"btn-danger",
7  confirmButtonText"Yes, delete it!",
8  cancelButtonText"No, cancel plx!",
9  closeOnConfirmfalse,
10  closeOnCancelfalse
11},
12function(isConfirm{
13  if (isConfirm) {
14    swal("Deleted!""Your imaginary file has been deleted.""success");
15  } else {
16    swal("Cancelled""Your imaginary file is safe :)""error");
17  }
18});

models.py

 1from django.db import models
2
3# Create your models here.
4
5class User(models.Model):
6    username = models.CharField(max_length=32, verbose_name='用户名')
7    age = models.IntegerField(verbose_name='年龄')
8    gender_choice = (
9        (1'male'),
10        (2'female'),
11        (3'others')
12    )
13    gender = models.IntegerField(choices=gender_choice, verbose_name='性别')

views.py

 1from django.shortcuts import render,  HttpResponse, redirect
2from app01 import models
3from django.http import JsonResponse
4from django.core import serializers
5
6
7def user_list(request):
8    user_queryset = models.User.objects.all()
9
10    return render(request, 'user_list.html', locals())
11
12def delete_user(request):
13    """
14    前后端在用ajax进行交互的时候,
15    后端通常给ajax的回调函数返回一个字典格式的数据
16    :param request:
17    :return:
18    """

19    if request.is_ajax():
20        if request.method == 'POST':
21            back_dic = {'code':1000'msg':''}
22            delete_id = request.POST.get('delete_id')
23            models.User.objects.filter(pk=delete_id).delete()
24            back_dic['msg'] = '数据删除成功!'
25            # 接下来需要告诉前端操作的结果
26            return JsonResponse(back_dic)   # 前端args  发送json格式数据

templates

 1<!DOCTYPE html>
2<html lang="en">
3<head>
4    <meta charset="UTF-8">
5    <title>Title</title>
6    <meta name="viewport" content="width=device-width, initial-scale=1">
7    {% load static %}
8    <link rel="stylesheet" href="{% static 'bootstrap-3.4.1-dist/css/bootstrap.min.css' %}">
9    <script src="{% static 'jQuery/jquery-3.6.0.min.js' %}"></script>
10    <script src="{% static 'bootstrap-3.4.1-dist/js/bootstrap.min.js' %}"></script>
11    <link rel="stylesheet" href="{% static 'dist/sweetalert.css' %}">
12    <script src="{% static 'dist/sweetalert.min.js' %}"></script>
13
14
15    <style>
16        div.sweet-alert h2{
17            padding-top10px;
18        }
19    </style>

20</head>
21<body>
22<div class="container-fluid">
23    <h1 class="text-center">数据展示</h1>
24    <div class="row">
25        <div class="col-md-8 col-md-offset-2">
26            <table class="table table-striped table-hover">
27                <thead>
28                    <tr>
29                        <th>序号</th>
30                        <th>用户名</th>
31                        <th>年龄</th>
32                        <th>性别</th>
33                        <th>操作</th>
34                    </tr>
35                </thead>
36                <tbody>
37                    {% for user_obj in user_queryset %}
38                        <tr>
39                            <td>{{ forloop.counter }}</td>
40                            <td>{{ user_obj.username }}</td>
41                            <td>{{ user_obj.age }}</td>
42{#                            这里的get_gender_display方法不要加括号   #}
43                            <td>{{ user_obj.get_gender_display }}</td>
44                            <td>
45                                <button class="btn btn-primary btn-xs edit">编辑</button>
46                                <button class="btn btn-danger btn-xs del" delete_id="{{ user_obj.pk }}">删除</button>
47                            </td>
48                        </tr>
49                    {% endfor %}
50
51                </tbody>
52            </table>
53        </div>
54    </div>
55</div>
56
57<script>
58    $('.del').on('click', function () {
59        // this  指代当前被操作对象本身
60        //alert($(this).attr('delete_id'));
61
62        // 先将当前标签对象存储起来
63        let currentBtn = $(this);
64
65        // 二次确认弹框定义  sweetalert
66        swal({
67          title: "你确定要删除吗?",
68          text: "删除后将无法恢复!",
69          type: "warning",
70          showCancelButton: true,
71          confirmButtonClass: "btn-danger",
72          confirmButtonText: "确认",
73          cancelButtonText: "取消",
74          closeOnConfirm: false,
75          closeOnCancel: false,
76         // showLoaderOnConfirm: true   // 延时删除
77        },
78        function(isConfirm) {
79          if (isConfirm) {
80              // 朝后端发送ajax请求删除数据,然后再弹出删除成功的界面提示
81              $.ajax({
82                  // url: '/delete/user/' + currentBtn.attr('delete_id'), // 传递主键值方式1
83                  url:'/delete/user/',  // 主键值直接放在请求体里面  方式2
84                  type: 'post',
85                  data: {'delete_id':currentBtn.attr('delete_id')},
86                  success:function (args) {  // args = {'code':'','msg':''}
87                      // 判断响应状态码 然后做不同的处理
88                        if(args.code === 1000){
89                            swal("删了!", args.msg, "success");
90                            // 1.lowb版本 直接刷新当前页面
91                            {#window.location.reload()#}
92                            // 2.利用DOM操作 动态刷新
93                            currentBtn.parent().parent().remove()
94                        }else{
95                            swal('完了','出现了未知错误','info')
96                        }
97                    }
98
99              })
100          } else {
101            swal("取消成功!", '', "error");
102          }
103        });
104
105    })
106</script>

107
108</body>
109</html>

settings.py

 1MIDDLEWARE = [
2    'django.middleware.security.SecurityMiddleware',
3    'django.contrib.sessions.middleware.SessionMiddleware',
4    'django.middleware.common.CommonMiddleware',
5    # 'django.middleware.csrf.CsrfViewMiddleware',
6    'django.contrib.auth.middleware.AuthenticationMiddleware',
7    'django.contrib.messages.middleware.MessageMiddleware',
8    'django.middleware.clickjacking.XFrameOptionsMiddleware',
9]
10
11
12STATIC_URL = '/static/'
13STATICFILES_DIRS = [
14    os.path.join(BASE_DIR, 'static')
15]



Ajax基本使用、基于Ajax请求的二次删除确认

Ajax基本使用、基于Ajax请求的二次删除确认



***************************************************************