• Django(九)下:Ajax操作、图片验证码、KindEditor使用


    三、Ajax操作

    ajax操作基于浏览器的xmlHttpRequest对象,IE低版本是另外一个对象,jQuery 1 版本对那两个对象做了封装,兼容性最好,2 、3版本不再支持IE低版本了。

    Ajax操作,用来偷偷发请求。

    参考博客:

    http://www.cnblogs.com/wupeiqi/articles/5703697.html

    1、原生Ajax操作

    XmlHttpRequest对象介绍

    • XmlHttpRequest对象的主要方法:
    void open(String method,String url,Boolen async)
       用于创建请求
    
       参数:
           method: 请求方式(字符串类型),如:POST、GET、DELETE...
           url:    要请求的地址(字符串类型)
           async:  是否异步(布尔类型)
    
    void send(String body)
        用于发送请求
    
        参数:
            body: 要发送的数据(字符串类型)
    
    void setRequestHeader(String header,String value)
        用于设置请求头
    
        参数:
            header: 请求头的key(字符串类型)
            vlaue:  请求头的value(字符串类型)
    
    String getAllResponseHeaders()
        获取所有响应头
    
        返回值:
            响应头数据(字符串类型)
    
    String getResponseHeader(String header)
        获取响应头中指定header的值
    
        参数:
            header: 响应头的key(字符串类型)
    
        返回值:
            响应头中指定的header对应的值
    
    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...

    原生ajax示例

    ajax.html

    <body>
        <input type="text" />
        <input type="button" value="Ajax1" onclick="Ajax1();" />
    
        <script>
            function Ajax1(){
                var xhr = new XMLHttpRequest();  // 创建XMLHttpRequest对象
                xhr.open('GET','/ajax_json/',true);
                xhr.onreadystatechange = function(){
                    if(xhr.readyState == 4){
                        // 接收完毕
                        var obj = JSON.parse(xhr.responseText);
                        console.log(obj)
                    }
                };
                xhr.setRequestHeader('k1','v1');  // 设置数据头
                xhr.send("name=root;pwd=123");
            }
        </script>
    </body>

    urls.py

        url(r'^ajax_json/', views.ajax_json),
        url(r'^ajax/', views.ajax),

    views.py

    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),status=404,reason='Not Found')  # 定义状态码及状态信息
        return HttpResponse(json.dumps(ret))

    上面发送的是GET请求,如果是POST请求呢?

    如上如果是POST请求,views里 print(request.POST) 是没有数据的,因为POST请求需要给加上请求头。

      <script>
            function Ajax1(){
                var xhr = new XMLHttpRequest();  // 创建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');  // 设置数据头
                xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset-UTF-8');
                xhr.send("name=root;pwd=123");
            }
        </script>

    兼容性问题

    以下几种写法,都是一样的效果

    > XMLHttpRequest
    XMLHttpRequest()
    > window.XMLHttpRequest
    XMLHttpRequest()
    > window['XMLHttpRequest']
    XMLHttpRequest()
    • XmlHttpRequest
      IE7+, Firefox, Chrome, Opera, etc.
    • ActiveXObject(“Microsoft.XMLHTTP”)
      IE6, IE5
     <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>

    jQuery的ajax

    如果在jquery的ajax的回调函数里,再写上一些参数,里面的参数接收的就是xmlHttpRequest对象,功能和上面是一模一样的。

    2、伪ajax(iframe标签)

    iframe标签,会把网址嵌套在网页中,iframe里的网址更改,网页是不刷新的。

    <iframe src="http://blog.csdn.net/lgeng00"></iframe>

    示例:输入 http://…… 网址,跳转

    <body>
        <input type="text" id="url" />
        <input type="button" value="Iframe请求" onclick="iframeRequest();" />
        <iframe src="http://blog.csdn.net/lgeng00" id="ifm"></iframe>
    
        <script src="/static/jquery-1.12.4.js"></script>
        <script>
            function iframeRequest(){
                var url = $('#url').val();
                console.log(url);
                $('#ifm').attr('src',url);
            }
        </script>
    </body>

    示例:iframe伪ajax提交

    可以把form提交转交给iframe,iframe提交,利用这个特性,实现伪ajax操作。

    ajax.html

        <form action="/ajax_json/" method="POST" target="ifm1">
            {% csrf_token %}
            <iframe id="ifm1" name="ifm1"></iframe>
            <input type="text" name="username" placeholder="用户名"/>
            <input type="text" name="email" placeholder="邮箱地址"/>
            <input type="submit" value="Form提交">
        </form>

    views.py

    def ajax_json(request):
        print(request.POST)
        ret = {'code':True, 'data':request.POST.get('username')}
        import json
        return HttpResponse(json.dumps(ret))

    阻止iframe里引用的网页自动跳转

    在一些新版本的浏览器里,iframe标签居然自动跳转,禁用如下:

    在iframe标签中增加两个属性:

    security="restricted" sandbox=""

    前者是IE的禁止js的功能,后者是HTML5的功能。刚好就可以让IE,Chrome,Firefox这三大浏览器都实现了禁止iframe的自动跳转。

    iframe获取返回的数据

    浏览器审查元素中,iframe加载的时候在document对象里,相当于一个上下文或者空间管理,在HTML里面又嵌套了一个HTML。不能通过以前的方法获取到。

    iframe接收到服务端返回的数据后,会执行onload事件,获取返回数据如下:

      <form action="/ajax_json/" method="POST" target="ifm1">
            {% csrf_token %}
            <iframe id="ifm1" name="ifm1" onload="iframeLoad();"></iframe>
            <input type="text" name="username" placeholder="用户名"/>
            <input type="text" name="email" placeholder="邮箱地址"/>
            <input type="submit" value="Form提交" onclick="submitForm();"/>
        </form>
    
        <script src="/static/jquery-1.12.4.js"></script>
        <script>
            function submitForm(){  // 当点击提交的时候,才给iframe绑定load事件
                // 比在html中这样添加好一点:<iframe name="ifm1" onload="iframeLoad();"></iframe>
                $('#ifm1').load(function(){
                    var text = $('#ifm1').contents().find('body').text();   // document对象下面的值
                    var obj = JSON.parse(text);
                    console.log(obj);
                })
            }
    
            function iiframeLoad(){
                console.log(123)
            }
        </script>

    ajax操作,使用方式选择

    如果发送的是【普通数据】 :  jQuery > XMLHttpRequest > iframe

    3、ajax 文件上传(三种方式)及 图片预览

    urls.py

        url(r'^upload/$', views.upload),
        url(r'^upload_file/', views.upload_file),

    views.py

    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)
        with open(img_path,'wb') as f:
            for item in fafafa.chunks():
                f.write(item)
    
        ret = {'code': True , 'data': img_path}  # 返回文件路径(图片预览用)
        import json
        return HttpResponse(json.dumps(ret))

    upload.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title></title>
        <style>
            .upload{
                display: inline-block;padding: 10px;
                background-color: #2459A2;
                color: white;
                position: absolute;
                top: 0;
                bottom: 0;
                right: 0;
                left: 0;
                z-index: 90;
            }
            .file{
                width: 60px;height: 30px;opacity: 0;
                position: absolute;
                top: 0;
                bottom: 0;
                right: 0;
                left: 0;
                z-index: 100;
            }
        </style>
    </head>
    <body>
        <div style="position: relative; 60px;height: 30px;">
            <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();" />
        <hr/>
    
        <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="iframe提交"/>   <!--iframe方式提交-->
            <hr>选中后,就上传、图片预览    <!--iframe方式提交,选中后,就上传,并图片预览-->
            <input type="file" name="fafafa" onchange="changeUpalod();" />  <!--iframe方式提交,选择后,就图片预览-->
        </form>
    
        <div id="preview"></div>  <!-- 图片预览使用 -->
    
        <script src="/static/jquery-1.12.4.js"></script>
        <script>
            // 选中后,就上传文件,并图片预览
            function changeUpalod(){
                $('#ifm1').load(function(){
                    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();
            }
    // 第二种方式:基于jQuery方式上传文件
            function jqSubmit(){
                // $('#fafafa')[0]
                var file_obj = document.getElementById('fafafa').files[0];  // files代表上传的文件
    
                var fd = new FormData();  // 相当于表单
                fd.append('username','root');
                fd.append('fafafa',file_obj);
    
                $.ajax({
                    url: '/upload_file/',
                    type: 'POST',
                    data: fd,
                    // 上传文件时,添加以下两个参数是告诉jQuery,不要做特殊处理
                    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);  // 多写几个参数,这个参数包含xmlHttpRequest对象
                    }
                })
            }
    // 第一种方式:基于xmlHttpRequest方式上传文件
            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);
            }
    // 第三种方式:基于iframe方式上传文件
            function iframeSubmit(){
                $('#ifm1').load(function(){
                    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);
                })
            }
    
        </script>
    </body>
    </html>

    xmlHttpRequest和jQuery上传文件,都是基于FormData,但是FormData对于IE一些低版本浏览器是不支持的。

    一般情况下,上传图片、头像都是用iframe来实现的。

    ajax操作,使用方式选择

    如果发送的是【文件】 :  iframe > jQuery(FormData) > XMLHttpRequest(FormData)

    四、图片验证码

    流程:

    • 访问页面 /login/
      • 创建一个图片并给用户返回
      • Session存放验证码
    • 用户POST提交数据,对比

    实现:

    页面生成返回和生成图片:生成网页html、生成图片url分开,这样更新验证码图片是,网页是不用刷新的。

    views

    from io import BytesIO
    from django.shortcuts import HttpResponse
    from utils.check_code import create_validate_code
    
    def check_code(request):
        """
        验证码
        :param request:
        :return:
        """
    # 直接打开图片,返回
        # data = open('static/imgs/avatar/20130809170025.png','rb').read()
        # return HttpResponse(data)
    
    # 通过模块生成图片并返回
        # 1. 创建一张图片 pip3 install Pillow
        # 2. 在图片中写入随机字符串
        # obj = object()
        # 3. 将图片写入到指定文件
        # 4. 打开指定目录文件,读取内容
        # 5. HttpResponse(data)
        stream = BytesIO()  # 在内存里开辟一块空间,在内存里直接读写,相当于打开一个文件
        img, code = create_validate_code()
        img.save(stream,'PNG')    # 把生成的图片进行保存
        request.session['CheckCode'] = code   # 把验证码放入session中
        return HttpResponse(stream.getvalue())  # 在内存中读取并返回

    create_validate_code

    font_type="Monaco.ttf",  # 依赖的字体

    html

    <img src="/check_code.html" onclick="changeCheckCode(this);">
    <script>
        function changeCheckCode(ths){
            ths.src = ths.src +  '?';  // URL不变:浏览器不发请求;加上?号,get参数请求,向后台发请求
        }
    </script>

    check_code.py(依赖:Pillow,字体文件)

    pip3 install Pillow

    五、KindEditor富文本编辑器

    常用的富文本编辑器:CKEditor,UEEditor,TinyEditor,KindEditor

    进入KindEditor官网

    文件夹说明

    ├── asp                          asp示例
    ├── asp.net                    asp.net示例
    ├── attached                  空文件夹,放置关联文件attached
    ├── examples                 HTML示例
    ├── jsp                          java示例
    ├── kindeditor-all-min.js 全部JS(压缩)
    ├── kindeditor-all.js        全部JS(未压缩)
    ├── kindeditor-min.js      仅KindEditor JS(压缩)
    ├── kindeditor.js            仅KindEditor JS(未压缩)
    ├── lang                        支持语言
    ├── license.txt               License
    ├── php                        PHP示例
    ├── plugins                    KindEditor内部使用的插件
    └── themes                   KindEditor主题

    基本使用

    <textarea name="content" id="content"></textarea>
    
    <script src="/static/jquery-1.12.4.js"></script>
    <script src="/static/plugins/kind-editor/kindeditor-all.js"></script>
    <script>
        $(function () {
            initKindEditor();
        });
    
        function initKindEditor() {
            var kind = KindEditor.create('#content', {
                 '100%',       // 文本框宽度(可以百分比或像素)
                height: '300px',     // 文本框高度(只能像素)
                minWidth: 200,       // 最小宽度(数字)
                minHeight: 400      // 最小高度(数字)
            });
        }
    </script>

    详细参数

    http://kindeditor.net/docs/option.html

    常用参数

    items¶          # 配置显示多少个工具
    noDisableItems¶ # designMode 为false时,要保留的工具,置灰
    filterMode¶     # true时根据 htmlTags 过滤HTML代码,false时允许输入任何代码。
    resizeType¶     # 2或1或0,2时可以拖动改变宽度和高度,1时只能改变高度,0时不能拖动。
    syncType¶       # 设置”“、”form”,值为form时提交form时自动提交,空时不会自动提交。
    uploadJson¶     # 指定上传文件的服务器端程序。
    autoHeightMode¶ # 内容多时,自动调整高度。
    • uploadjson
    <textarea id="content"></textarea>
    
    <script src="/static/jquery-1.12.4.js"></script>
    <script src="/static/kindeditor-4.1.10/kindeditor-all.js"></script>
    <script>
            KindEditor.create('#content', {
                uploadJson: '/upload_img/',
                fileManagerJson: '/file_manager/',  // 文件管理路径
                allowImageRemote: true,  // 是否允许远程上传
                allowImageUpload: true,  // 是否允许本地上传
                allowFileManager: true,  // 图片空间,文件预览功能
                extraFileUploadParams: { // CSRF限制,提交csrf
                    csrfmiddlewaretoken: "{{ csrf_token }}"
                },
                filePostName: 'fafafa'   // 设置文件发送的name值,方便后台获取
            });
        })
    </script>
    def upload_img(request):
        request.GET.get('dir')
        print(request.FILES.get('fafafa'))
        # 获取文件保存
        import json
        dic = {
            'error': 0,
            'url': '/static/imgs/20130809170025.png',
            'message': '错误了...'
        }
        return HttpResponse(json.dumps(dic))
    
    import os, time, json
    def file_manager(request):
        """
        文件管理,照片空间
        :param request:
        :return:
        """
        dic = {}
        root_path = 'C:/Users/Administrator/PycharmProjects/day24/static/'
        static_root_path = '/static/'
        request_path = request.GET.get('path')
        if request_path:
            abs_current_dir_path = os.path.join(root_path, request_path)
            move_up_dir_path = os.path.dirname(request_path.rstrip('/'))
            dic['moveup_dir_path'] = move_up_dir_path + '/' if move_up_dir_path else move_up_dir_path
    
        else:
            abs_current_dir_path = root_path
            dic['moveup_dir_path'] = ''
    
        dic['current_dir_path'] = request_path
        dic['current_url'] = os.path.join(static_root_path, request_path)
    
        file_list = []
        for item in os.listdir(abs_current_dir_path):
            abs_item_path = os.path.join(abs_current_dir_path, item)
            a, exts = os.path.splitext(item)
            is_dir = os.path.isdir(abs_item_path)
            if is_dir:
                temp = {
                    'is_dir': True,
                    'has_file': True,
                    'filesize': 0,
                    'dir_path': '',
                    'is_photo': False,
                    'filetype': '',
                    'filename': item,
                    'datetime': time.strftime('%Y-%m-%d %H:%M:%S', time.gmtime(os.path.getctime(abs_item_path)))
                }
            else:
                temp = {
                    'is_dir': False,
                    'has_file': False,
                    'filesize': os.stat(abs_item_path).st_size,
                    'dir_path': '',
                    'is_photo': True if exts.lower() in ['.jpg', '.png', '.jpeg'] else False,
                    'filetype': exts.lower().strip('.'),
                    'filename': item,
                    'datetime': time.strftime('%Y-%m-%d %H:%M:%S', time.gmtime(os.path.getctime(abs_item_path)))
                }
    
            file_list.append(temp)
        dic['file_list'] = file_list
        return HttpResponse(json.dumps(dic))

    转载请务必保留此出处:http://www.cnblogs.com/lgeng/articles/7382196.html 

    <!-- END  -->

    《版本说明》: 本文转自 -- http://blog.csdn.net/fgf00/article/details/54917439

  • 相关阅读:
    Ducking
    MINITAB(二)
    JFreechart
    linux命令0424
    JAVA哈哈镜
    HTML(四)
    The 3n+1 problem
    [转载]:【读书笔记】.NET本质论
    ER图基本步骤
    [从架构到设计]第一回:设计,应该多一点(转载)
  • 原文地址:https://www.cnblogs.com/lgeng/p/7382196.html
Copyright © 2020-2023  润新知