zoukankan      html  css  js  c++  java
  • Ajax的原理及Django上传组件


    title: Ajax的原理及Django上传组件
    tags: Django

    Ajax的原理及Django上传组件

    Ajax的原理

    ajax 是异步JavaScript和xml

    ajax就是向后台提交数据但是不刷新页面

    原生Ajax XMLHttprequest

    • 创建一个XMLHttprequest对象
    • 回调函数onreadystatechange 对应jQuery中的success
    • 状态值是不断变化的,4代表完成,已经接收到全部响应数据;
    • open是创建请求
    • send是发送数据

    XMLHttprequest对象的主要方法:

    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的主要属性

    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中发用的数据

    <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>
    
    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 没有设置请求头的情况

    	<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中

    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("...")
    

    结果:

    <QueryDict: {}>  post中没有数据
    b'i1=1&i2=3'  body总的数据
    
    

    2 设置请求头

    • xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded');
        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的计算器

    <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>
    
    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的应用

    <!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=" 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进行发送

    <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会是未定义
    <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的对象

    <script>
        function submitForm() {
            document.getElementById('ifr').onload = loadIframe;  // 绑定事件后执行函数
            document.getElementById('f1').submit();  //js提交表单
        }
        //回调函数
        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发送字符串

    <!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对象发送
                formData.append('k1','v1');
                var xhr = new XMLHttpRequest();
                xhr.onreadystatechange = function () {
                    if(xhr.readyState==4){
                        alert(xhr.responseText)
                    }
                };
                xhr.open('POST','/upload/'); // 第一个参数是method 第二个是URL 第三个是默认异步
                xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded'); //添加请求头
                xhr.send(formData);  //发送formData对象
            };
        </script>
    
    </body>
    </html>
    

    后台获取的数据:

        def upload(request):
        if request.method == "GET":
            return render(request, 'upload.html')
        else:
            print(request.POST)  # 查看POST获取的信息
            return HttpResponse('...')
    

    结果:

    <QueryDict: {'------WebKitFormBoundaryyPbfiKT1zk4kFYTP
    Content-Disposition: form-data': [''], ' name': ['"k1"
    
    v1
    ------WebKitFormBoundaryyPbfiKT1zk4kFYTP--
    ']}>
    

    1.1 formdata对象发送字符串

    上面的情况是加上了请求头,这是自己用原生的XMLHttpresponse发送数据的时候

    而formdata能够自动处理发送的数据(字符串、文件)

    formdata发送字符串在后台直接获取

    <!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对象发送
                formData.append('k1','v1');
                var xhr = new XMLHttpRequest();
                xhr.onreadystatechange = function () {
                    if(xhr.readyState==4){
                        alert(xhr.responseText)
                    }
                };
                xhr.open('POST','/upload/'); // 第一个参数是method 第二个是URL 第三个是默认异步
                xhr.send(formData);  //发送formData对象
            };
        </script>
    
    </body>
    </html>
    

    后台获取的数据:

    <QueryDict: {'k1': ['v1']}>
    
    

    2 formdata对象发送文件

    • 创建FormData对象
    • 添加要发送的文件对象的,是一个列表,包含文件的信息document.getElementById('i1').files[0]
    • send(formdata) 最后发送的是formdata对象
    <!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对象发送
                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/'); // 第一个参数是method 第二个是URL 第三个是默认异步
                xhr.send(formData);  //发送formData对象
            }
        </script>
    
    </body>
    </html>
    

    后台

    • 获取文件对象file_obj, request.FILES.get('upload_file'),文件名和前端对应
    • 这个文件对象打印出来的是文件的名字
    • 文件对象中chunks()是存在内存中的。保存文件要从内存保存到本地
    • 拼接文件路径
    • 把文件的路径返回到前端
        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')  # 获取上传文件的对象,获取的是formdata对象的第一个参数名
            print(file_obj) # file_obj 是文件本身 打印出来的是文件的名字
            print("...")
            print(file_obj.chunks())  # 这个是内存中的 <generator object InMemoryUploadedFile.chunks at 0x000000000461EF10>
            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():  # 这里是chunks()  写错了chunks
                    f.write(chunk)
            return HttpResponse(file_path)  # 把文件的路径返回到前端
    

    3 ajax上传图片并预览

    • 返回上传文件的路径
    • 路径加 / + file_path 进行拼接
    • 动态创建img 添加src
    • 找到div appendchild
    <!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对象发送
                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');  // 动态创建img标签
                        tag.src ='/'+ file_path; // 静态文件路径的开头有 斜杠
                        document.getElementById('container1').appendChild(tag); // 把img 添加到container1
                    }
                };
                xhr.open('POST','/upload/'); // 第一个参数是method 第二个是URL 第三个是默认异步
                xhr.send(formData);  //发送formData对象
            }
        </script>
    </body>
    </html>
    

    使用jQuery

    jQuery内部也是用的XMLHttpresquest,也是用formdata,还需要告知jQuery不在请求头添加内容

    contentType:false,processData:false,

    否则遇到的错误是:Uncaught TypeError: Illegal invocation

    DOM 对象和jQuery对象的转换

        jQuery -> DOM :$('#i2')[0] # 取0就是第一个元素
        DOM -> jQuery  : $(document.getElementById('i2'))  #直接加$
    

    http://www.cnblogs.com/Python666/p/6925517.html

    <!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中 与后台的获取文件对象的名字一致
    <!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

  • 相关阅读:
    Java学习之IO之File类一
    Java学习之二分查找算法
    Java学习之国际化程序
    Java学习之自定义异常
    Java学习之开篇—个人随想
    pl/sql 的 put和put_line区别
    Java中static、final用法
    一个包含所有c++的头文件的头文件
    Codeforces Round #379 (Div. 2)
    hdu-5977 Garden of Eden(树分治)
  • 原文地址:https://www.cnblogs.com/Python666/p/7143795.html
Copyright © 2011-2022 走看看