摘要:ThinkPHP是一個小型網站很常用的低端框架,但是不專業的文檔和編碼導致使用者很容易只知其表不知其里。這裡僅就官方文檔中未曾提及的在thinkphp中使用jquery實現ajax非同步交互略作總結。 環境:ThinkPHP3.2.3,jQuery 閱讀目錄: 正文: 在一般的網站中,都需要用到 ...
摘要:ThinkPHP是一個小型網站很常用的低端框架,但是不專業的文檔和編碼導致使用者很容易只知其表不知其里。這裡僅就官方文檔中未曾提及的在thinkphp中使用jquery實現ajax非同步交互略作總結。
環境:ThinkPHP3.2.3,jQuery
閱讀目錄:
正文:
在一般的網站中,都需要用到jquery或者其他框架(比如angular)來處理前後端數據交互。在thinkphp在後臺也內置了一些函數用於數據交互(比如ajaxReturn())。本文的目的是打通jquery ajax到thinkphp的前後端數據交互過程。
前言:
一、thinkphp關於ajax的介紹
1.1 ajaxReturn:
\Think\Controller類提供了ajaxReturn方法用於AJAX調用後返回數據給客戶端(視圖、模板、js等)。並且支持JSON、JSONP、XML和EVAL四種方式給客戶端接受數據(預設JSON)。(鏈接:http://document.thinkphp.cn/manual_3_2.html#ajax_return)
配置方式: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.(鏈接:http://php.net/manual/en/function.json-encode.php)
舉例:
$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 當前提交類型
目的:一方面可以針對請求類型作出不同的邏輯處理,另外一方面可以過濾不安全的請求。 (鏈接:http://document.thinkphp.cn/manual_3_2.html#request_method)
使用方法:
class UserController extends Controller{
public function update(){
if (IS_POST){
$User = M('User');
$User->create();
$User->save();
$this->success('保存完成');
}else{
$this->error('非法請求');
}
}
}
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
舉例:
在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對象。
下麵有兩種轉換方法:http://blog.jdk5.com/zh/convert-form-data-to-javascript-object-with-jquery/
這裡使用第二種方法舉例,可以起名為change_serialize_to_json():
var data = {};
$("form").serializeArray().map(function(x){
if (data[x.name] !== undefined) {
if (!data[x.name].push) {
data[x.name] = [data[x.name]];
}
data[x.name].push(x.value || '');
} else {
data[x.name] = x.value || '';
}
});
輸出:{"input1":"","textarea":"234","select":"1"}
完整流程:
var serialize=$('#form').serialize()結果(得到一個字元串,用serializeArray()更好,其中中文都會轉換成utf8):
serial_number=SN2&result=%E9%9D%9E%E6%B3%95
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()相反,用於從一個對象解析出字元串。
(鏈接:http://blog.csdn.net/wangxiaohu__/article/details/7254598)
str_replace() 函數用於替換掉字元串中的特定字元,比如替換掉數據轉換後多餘的空格、'/nbsp'等
註意:serialize和serializeArray()函數在處理checkbox時存在無法獲取未勾選項的bug,需要自己編寫函數改寫原函數,舉例:
(鏈接:http://www.cnblogs.com/tangge/p/6554891.html)
//value賦值為off是因為正常的serializeArray()獲取到的勾選的checkbox值為on。
$.fn.mySerializeArray = function () {
var a = this.serializeArray();
var $radio = $('input[type=radio],input[type=checkbox]', this);
var temp = {};
$.each($radio, function () {
if (!temp.hasOwnProperty(this.name))
{
if ($("input[name='" + this.name + "']:checked").length == 0)
{
temp[this.name] = "";
a.push({name: this.name, value: "off"});
}
}
});
return a;
};
三、使用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();
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)
{
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字元串而已
dataType: "json",
success: function (data) {
console.log("數據交互成功");
},
error: function (data) {
console.log("數據交互失敗");
}
});
}
else
{
//彈出錯誤提示alert
}
return 0;
}
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);
$posted_json_data_replace_array = (Array)json_decode($posted_json_data_replace);
//處理資料庫事務寫入,通過判斷寫入結果來區分ajaxReturn的結果
//可以將所有想要返回的數據放在一個數組中,比如新增的行id、插入資料庫的操作是否成功
//如果操作資料庫成功就返回如下結果。
$user_table->commit();
$data['result'] = true;
$data['pk_user_id'] = $data_add_user_result;
$this->ajaxReturn($data);
return 0;
}
}
改寫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非同步局部刷新。