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
   狀態碼(整數),如:200404...

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/fgf00"></iframe>

示例:輸入http://……網址,跳轉

<body>
    <input type="text" id="url" />
    <input type="button" value="Iframe請求" onclick="iframeRequest();" />
    <iframe src="http://blog.csdn.net/fgf00" 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" οnlοad="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;width: 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', {
            width: '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://blog.csdn.net/fgf00/article/details/54917439

發佈了102 篇原創文章 · 獲贊 116 · 訪問量 64萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章