jquery ajax thinkphp異步局部刷新完整流程


環境:ThinkPHP3.2.3,jQuery3.2
 
前言:
在一般的網站中,都需要用到jquery或者其他框架(比如angular)來處理前后端數據交互,thinkphp在后台也內置了一些函數用於數據交互(比如ajaxReturn())。本文的目的是打通使用ajax在jquery和thinkphp之間的前后端數據交互過程。
 
正文:
一、thinkphp關於ajax的介紹
1.1 ajaxReturn:
\Think\Controller類提供了ajaxReturn方法用於AJAX返回數據給客戶端(視圖、模板、js等)。並且支持JSON、JSONP、XML和EVAL四種方式給客戶端接受數據(默認JSON)。
配置方式:convention.php中定義了默認編碼類型為DEFAULT_AJAX_RETURN => 'JSON',
分析:ajaxReturn()調用了json_encode()將數值轉換成json數據存儲格式,常用的數值是數組。
注意:The value being encoded can be any type except a resource(資源文件).All string data must be UTF-8 encoded.
舉例:
$data['status'] = 1;
$data['content'] = 'content';
$this->ajaxReturn($data);
1.2 請求類型:
系統內置了一些常量用於判斷請求類型,比如:
常量 說明
IS_GET 判斷是否是GET方式提交
IS_POST 判斷是否是POST方式提交
IS_PUT 判斷是否是PUT方式提交
IS_DELETE 判斷是否是DELETE方式提交
IS_AJAX 判斷是否是AJAX提交
REQUEST_METHOD 當前提交類型
目的:一方面可以針對請求類型作出不同的邏輯處理,另外一方面可以過濾不安全的請求。
使用方法:
class UserController extends Controller{
     public function update(){
         if (IS_POST){
             $User = M('User');
             $User->create();
             $User->save();
             $this->success('保存完成');
         }else{
             $this->error('非法請求');
         }
    return 0;
     }
}

1.3 跳轉和重定向:

功能比較雞肋,在ajax異步交互局部刷新中,不需要有文字提示的跳轉。(鏈接: http://document.thinkphp.cn/manual_3_2.html#page_jump_redirect
 
二、jQuery Ajax的介紹:
2.1 官網關於jQuery.ajax()的介紹:
jQuery.ajax() 方法用於執行 AJAX(異步 HTTP)請求。(鏈接: http://www.jquery123.com/jQuery.ajax/
語法:$.ajax({name:value, name:value, ... }),該參數規定 AJAX 請求的一個或多個名稱/值對。
常見參數:
type (默認: 'GET')
類型: String
請求方式 ("POST" 或 "GET"), 默認為 "GET"。注意:其它 HTTP 請求方法,如 PUT 和 DELETE 也可以使用,但僅部分瀏覽器支持。
url (默認: 當前頁面地址)
類型: String
發送請求的地址。
async (默認: true)(1.8版本已棄用)
類型: Boolean
默認設置下,所有請求均為異步請求(也就是說這是默認設置為 true )。如果需要發送同步請求,請將此選項設置為 false 。
data
類型: Object, String
發送到服務器的數據。將自動轉換為請求字符串格式。GET 請求中將附加在 URL 后面。查看 processData 選項說明,以禁止此自動轉換。對象必須為"{鍵:值}"格式。如果這個參數是一個數組,jQuery會按照traditional 參數的值, 將自動轉化為一個同名的多值查詢字符串(查看下面的說明)。注:如 {foo:["bar1", "bar2"]} 轉換為 '&foo=bar1&foo=bar2'。
dataType (默認: Intelligent Guess (xml, json, script, or html))
類型: String
預期服務器返回的數據類型。如果不指定,jQuery 將自動根據 HTTP 包 MIME 信息來智能判斷,比如XML MIME類型就被識別為XML。在1.4中,JSON就會生成一個JavaScript對象,而script則會執行這個腳本。隨后服務器端返回的數據會根據這個值解析后,傳遞給回調函數。舉例:
"json": 把響應的結果當作 JSON 執行,並返回一個JavaScript對象。在 jQuery 1.4 中,JSON 格式的數據以嚴格的方式解析,如果格式有錯誤,jQuery都會被拒絕並拋出一個解析錯誤的異常。(見json.org的更多信息,正確的JSON格式。)
error
類型: Function( jqXHR jqXHR, String textStatus, String errorThrown )
請求失敗時調用此函數。有以下三個參數:jqXHR (在 jQuery 1.4.x前為XMLHttpRequest) 對象、描述發生錯誤類型的一個字符串 和 捕獲的異常對象。如果發生了錯誤,錯誤信息(第二個參數)除了得到null之外,還可能是"timeout", "error", "abort" ,和 "parsererror"。 當一個HTTP錯誤發生時,errorThrown 接收HTTP狀態的文本部分,比如: "Not Found"(沒有找到) 或者 "Internal Server Error."(服務器內部錯誤)。 從jQuery 1.5開始, 在error設置可以接受函數組成的數組。每個函數將被依次調用。 注意:此處理程序在跨域腳本和JSONP形式的請求時不被調用。這是一個 Ajax Event。
success
類型: Function( Object data, String textStatus, jqXHR jqXHR )
請求成功后的回調函數。這個函數傳遞3個參數:從服務器返回的數據,並根據dataType參數進行處理后的數據,一個描述狀態的字符串;還有 jqXHR(在jQuery 1.4.x前為XMLHttpRequest) 對象 。在jQuery 1.5, 成功設置可以接受一個函數數組。每個函數將被依次調用。這是一個 Ajax Event
其他jQuery-ajax-settings,詳見:http://www.jquery123.com/#jQuery-ajax-settings
jQuery重要參數

舉例:

在js中把id作為數據發送到服務器, 保存一些數據到服務器上, 一旦請求完成就通知用戶。 如果請求失敗,則提醒用戶。
var menuId = $("ul.nav").first().attr("id");
var request = $.ajax({
  url: "script.php",
  type: "POST",
  data: {id : menuId},
  dataType: "html"
}); 
request.done(function(msg) {
  $("#log").html( msg );
}); 
request.fail(function(jqXHR, textStatus) {
  alert( "Request failed: " + textStatus );
});

注意:此處也可以在ajax()中使用success和error參數判斷請求結果成功還是失敗,並執行下一步操作。

 
2.2 js與json
2.2.1 json是什么:
JSON:JavaScript 對象表示法(JavaScript Object Notation)。是獨立於語言之外的存儲和交換文本信息的語法。
2.2.2 json和ajax的關系?
在上面關於jquery.ajax的介紹中提到了,json可以作為一個ajax函數的dataType,這樣數據就會通過json語法傳輸了。(鏈接: http://www.cnblogs.com/haitao-fan/p/3908973.html
在jquery的ajax函數中,只能傳入3種類型的數據:(鏈接: http://www.cnblogs.com/haitao-fan/p/3908973.html
>1.json字符串:"uname=alice&mobileIpt=110&birthday=1983-05-12"
>2.json對象:{uanme:'vic',mobileIpt:'110',birthday:'2013-11-11'}
>3.json數組:
[
{"name":"uname","value":"alice"},
{"name":"mobileIpt","value":"110"},
{"name":"birthday","value":"2012-11-11"}
]
2.2.3 json的編解碼和數據轉換:
2.2.2中提到的json對象是更方便與js數組、js字符串或php數組、php字符串進行數據轉化的json類型。下面以json對象為例講解一下json對象與js和php的數據類型轉化。
json對象轉化成數組:
<script type="text/javascript">
     var jsonStr = '[{"id":"01","open":false,"pId":"0","name":"A部門"},{"id":"01","open":false,"pId":"0","name":"A部門"},{"id":"011","open":false,"pId":"01","name":"A部門"},{"id":"03","open":false,"pId":"0","name":"A部門"},{"id":"04","open":false,"pId":"0","name":"A部門"}, {"id":"05","open":false,"pId":"0","name":"A部門"}, {"id":"06","open":false,"pId":"0","name":"A部門"}]';
     //  var jsonObj = $.parseJSON(jsonStr);
     var jsonObj =  JSON.parse(jsonStr)
     console.log(jsonObj)
     var jsonStr1 = JSON.stringify(jsonObj)
     console.log(jsonStr1+"jsonStr1")
     var jsonArr = [];
     for(var i =0 ;i < jsonObj.length;i++){
            jsonArr[i] = jsonObj[i];
     }
     console.log(typeof(jsonArr))
</script>

想要將表單數據提交到后台,需要先從表單獲取數據/數據集:

serialize和serializeArray的區別是serialize()獲取到序列化的表單值字符串,serializeArray()以數組形式輸出序列化表單值。舉例:
var serialize_string=$('#form').serialize();
得到:a=1&b=2&c=3&d=4&e=5
var serialize_string_array=$('#form').serializeArray();
得到:
[
{name: 'firstname', value: 'Hello'},
{name: 'lastname', value: 'World'},
{name: 'alias'}, // 值為空
]
相對來說,serializeArray()和最終想要得到的json數組更加相似。只不過需要將包含多個name-value形式json對象的json數組改寫成'first_name':'Hello'形式的json對象。
這里使用第一種方法舉例,傳入的參數是serializeArray()函數的結果,並且稍作優化,可以起名為change_serialize_to_json():
function change_serialize_to_json(serialize_objective_array) {
    var temp_json_object = {};
    $.each(serialize_objective_array, function () {
        temp_json_object[this.name] = this.value;
    });
    return temp_json_object;
}

輸出:{"input1":"","textarea":"234","select":"1"}

 
2.2.4完整流程:
var serialize_array=$('#form').serializeArray()結果(結果是json對象數組):
Array [ Object, Object ]
var data=change_serialize_to_json(serialize_array)的結果是(以第二種轉換方法為例,結果是json對象):
Object {serial_number: "SN2", result: "非法" }
var json_data=JSON.stringify(data)(結果是json字符串):
{"serial_number":"SN2","result":"非法"}
 
在js端將表單數據轉化為json形式的其他函數:
將json字符串轉換為json對象:
eval("(" + status_process+ ")");
json字符串轉化成json對象:
// jquery的方法
var jsonObj = $.parseJSON(jsonStr)
//js 的方法
var jsonObj =  JSON.parse(jsonStr)
json對象轉化成json字符串:
//js方法
var jsonStr1 = JSON.stringify(jsonObj)
JSON.parse()用於從一個字符串中解析出json對象。JSON.stringify()相反,用於從一個對象解析出字符串。
 
str_replace() 函數用於替換掉字符串中的特定字符,比如替換掉數據轉換后多余的空格、'/nbsp'等
 
注意:serialize和serializeArray()函數在處理checkbox時存在無法獲取未勾選項的bug,需要自己編寫函數改寫原函數,舉例:
(鏈接:http://www.cnblogs.com/tangge/p/6554891.html)
//value賦值為off是因為正常的serializeArray()獲取到的勾選的checkbox值為on。
$.fn.my_serialize_array = function () {
    var my_serialize_array = this.serializeArray();//官方函數只包含勾選的checkbox,並且值默認為on
    var not_checked_object = $('input[type=checkbox]:not(:checked)', this);//this指調用這個函數的form
    $.each(not_checked_object, function () {
        if (!my_serialize_array.hasOwnProperty(this.name))
        {//this指沒選中的一個object
            my_serialize_array.push({name: this.name, value: "off"});
        }
    });
    console.log(my_serialize_array);
    return my_serialize_array;
};

 

三、使用js操作DOM實現異步局部刷新的完整流程:
實現局部刷新的途徑:
1、假設頁面有查詢form和結果table。
2、點擊查詢form的提交,觸發js自定義的submit事件,在submit函數中對獲取的表單數據檢測后如果符合要求就傳遞給控制器,控制器從數據庫獲取結果數組后返回給ajax的success。對返回給ajax的結果數組,可以創建一個refresh()函數,或直接在success中用jQuery(或其他js)操縱結果table(DOM),比如刪除tbody節點下的所有內容,並將結果數組格式化后添加到tbody下面。
舉例:
//1、php中的form表單
<div class="modal fade hide" id="add_engineer_modal" tabindex="-1" role="dialog">
......
<form id="add_engineer_modal_form" class="form-horizontal">
<fieldset>
......
<button type="button" class="btn btn-primary" id="add_engineer_modal_submit" onclick="add_engineer_modal_submit()" >提交更改</button>
......
</fieldset>
</form>
</div>

 

//2、js校驗表單並發起ajax
function add_engineer_modal_check_value() {
    //以edit_modal_check_value()為模板
    var serialize_array_object = $("#add_engineer_modal_form").mySerializeArray();//針對checkbox優化的SerializeArray
    var data = change_serialize_to_json(serialize_array_object);
    var check_results = [];
    check_results['result'] = [];//保存錯誤信息
    check_results['data'] = data;//保存input和select對象
    //check_employee_number是自定義判斷員工號函數。
    if (check_employee_number(data['employee_number']) == false)
    {
        check_results['result'].push("請輸入有效的員工號(可選)");
    }
    return check_results;
}

function add_engineer_modal_submit() {
    var check_results = add_engineer_modal_check_value();
    if (check_results['result'].length == 0)
    {
    //注意,是否要轉換上面的data,要取決於你想要用什么類型傳輸,用js對象傳輸更好,不需要stringify,也方便控制器處理。我的舊代碼有些累贅了。
        var json_data = JSON.stringify(check_results['data']);   //JSON.stringify() 方法將一個JavaScript值轉換為一個JSON字符串(ajax要求json對象或json字符串才能傳輸)
        $.ajax({
            type: 'POST',
            url: add_engineer_url,        //在php中全局定義url,方便使用thinkphp的U方法
            data: {"json_data": json_data},            //ajax要求json對象或json字符串才能傳輸,json_data只是json字符串而已。如果上面用js對象傳輸,這里就寫成"data:json_data,"
            dataType: "json",
            success: function (data) {
                console.log("數據交互成功");
            },
            error: function (data) {
                console.log("數據交互失敗");
            }
        });
    }
    else
    {
        //彈出錯誤提示alert
    }
    return 0;
}
注意:此處的add_engineer_url一般定義在函數之前,由於我有很多函數可能要用到這個url,我一般寫在js最前面。當然也可以寫在php的head之內,那樣就可以使用U方法自動生成url。
 
3、控制器檢查數據操作數據庫並返回數組給js
public function add_engineer() {
        if (IS_AJAX)
        {
            $posted_json_data = I('post.json_data');
            $posted_json_data_replace = str_replace('"', '"', $posted_json_data);//慎用str_replace,如果非要用最好在轉成數組之后,針對特定的item替換。舊代碼這樣寫不太好。
            $posted_json_data_replace_array = (Array)json_decode($posted_json_data_replace);//一般不需要強制Array,json_decode的返回值就是Array,此處我是為了防止自己的serializeArray產生了特殊值影響到這里。最好還要有一些過濾函數過濾掉script、html元素等
               
               //處理數據庫事務寫入,通過判斷寫入結果來區分ajaxReturn的結果
              //可以將所有想要返回的數據放在一個數組中,比如新增的行id、插入數據庫的操作是否成功
              //如果操作數據庫成功就返回如下結果。
               $user_table->commit();//省略事務等操作
            $data['result'] = true;
            $data['pk_user_id'] = $data_add_user_result;
            $this->ajaxReturn($data);//省略條件判斷,建議對正反條件都返回數組,比如$data['alert']記錄返回結果true還是false,如果是true,就把$data['result']=$result,返回$data。
        }
        return 0;
    }
注意:一定不要在有ajaxReturn的函數中添加打印(echo、var_dump等),這會導致ajax error。如果要在F12下調試,可以注釋掉ajaxReturn,也可以直接看交互過程的錯誤提示。
 
4、改寫js:
在js的ajax中,如果整個ajax正常交互,就會走success函數,否則會走error函數,一般情況下,error出現的原因都是傳輸的數據不符合要求。
在success中的data就是ajaxReturn中傳輸的數組,舉例:
success: function (data) {
                if (data['result'] == false)
                {
                    alert(data['alert']);
                }
                else
                {
                    $('#add_engineer_modal').modal('hide');
                    $('#user_list_table tr').eq(0).after('<tr></tr>');
                    //這里就可以使用data['pk_user_id']了。
                    $('#user_list_table tr').eq(1).append('<td>'+data['pk_user_id']+'</td>');
                }
            },
  
四、總結
整個過程是:
在php中編寫頁面中的表單、提交按鈕等;
在js中對php中的按鈕事件添加校驗和觸發函數,在js函數內,如果js對象的格式和內容正確就向控制器url(php中初始化)發起ajax請求;
控制器中的相應操作響應ajax請求,並判斷數據后做數據庫讀寫操作,然后對數據庫操作結果做出判斷,ajaxReturn返回js需要的數組;
當ajax成功返回時,js中ajax的success里面使用js重寫(或初始化)需要顯示的信息。
這樣就完成了ajax異步局部刷新。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM