Ajax+PHP實現動態無刷新技術應用及其普遍,由於它有着可動態的實現WEB頁面局部刷新,減輕服務器端負擔,按需取數據,能帶來更好的用戶體驗的優點。主要適用的場景像一些表單驅動的交互,普通的文本輸入提示和自動完成,投票yes/no等無關痛癢的場景等等。根據文章的標題,你們應該看出來了,我在「部門和人員」這一模塊當中就用了無刷新的技術,一併結合Yii2自帶的Csrf驗證。在這麼使用的時候,我遇到了一些問題,也想出了一些解決方式,今天花了點時間整理一下,分享了。javascript
一、作一個部門和人員模塊所有使用Aajx無刷新技術開發。
二、要求使用Yii2自帶的Csrf驗證。php
部門和人員模塊效果html
Csrf驗證java
結合需求,在點擊的按鈕上所有加上onClick點擊事件,而後function事件的方法經過Ajax把數據傳到控制器處理,返回進行局部刷新頁面,查看結果是否正確,實現思路大體就這樣。這麼說可能還有人迷糊,下面我附上代碼,因代碼量太大,因此我只附關鍵部分。ajax
以添加員工爲例:數組
一、視圖部分服務器
點擊添加員工按鈕,在添加員工按鈕上定義個onClick="AddUser()"事件,由於我用的是a標籤,因此爲了不雙重點擊跳轉,這裏我把a標籤裏的href設爲「javascript:void(0);」禁止跳轉。yii2
<a style="margin-left: 130px;" class="btn btn-success" onClick="AddUser()" href="javascript:void(0);"><i class="glyphicon glyphicon-plus"></i> 添加員工</a>
點擊提交表單按鈕,經過Ajax提交。注意這裏我使用的是Button,而不是submitButton,使用submitButton沒法實現無刷新。app
<?php echo Html::Button(Yii::t('yii', 'Create'), ['class' =>'btn btn-primary','onClick'=>"UUpdate1()"]) ?>
二、JS部分。yii
我分紅兩步走,第一步是點擊添加展現視圖頁面,第二部分是添加部門提交表單驗證,返回局部刷新頁面。
第一步: //列表添加員工 function AddUser(){ $.ajax({ type : "post", url : "/department/tree", dataType : "text", data : {'AddUser':'AddUser'}, //固定參數,區分用 success : function(data){ $('#href_data').html(data); } }); }
第二步: //列表添加員工提交表單驗證 function AddUser1(){ var id=$("#current_dep").val(); var company_id=$("#current_com").val(); var parent_id=$('#user-parent_id').val(); var t_nickname=$('#user-t_nickname').val(); var t_realname=$('#user-t_realname').val(); var t_mobile=$('#user-t_mobile').val(); var t_email=$('#user-t_email').val(); //獲取選中部門 var arr = document.getElementsByName('department_ids[]'); var arrLen = arr.length; var chk = []; var chkPoint = 0; for (var i = 0; i < arrLen; i ++) { if(arr[i].checked == true){ chk[chkPoint] = arr[i].value; chkPoint ++; } } //獲取選中職位 var posit = document.getElementsByName("UserProfile[position][]"); var arrlen = posit.length; var position = []; var chkpoint = 0; for (var i = 0; i < arrlen; i ++) { if(posit[i].checked == true){ position[chkpoint] = posit[i].value; chkpoint ++; } } //暱稱,真實姓名,郵箱同時存在才能提交表單 if(t_nickname && t_realname && t_email){ $.ajax({ type : "post", url : "/department/tree", dataType : "text", data : { 'UId':id, 'UCompany_id':company_id, 'SEdit':'SEdit', 'add_user':'add_user', 'User[parent_id]':parent_id, 'User[t_nickname]':t_nickname, 'User[t_realname]':t_realname, 'User[t_mobile]':t_mobile, 'User[t_email]':t_email, 'department_ids':chk, 'UserProfile[position]':position, '_csrf':'<?php echo Yii::$app->request->getCsrfToken (); ?>' }, success : function(data){ $('#href_data').html(data); } }); }else{ $.ajax({ type : "post", url : "/department/tree", dataType : "text", data : {'UId':id,'UCompany_id':company_id,'SEdit':'SEdit','add_user':'add_user','User[t_nickname]':t_nickname,'User[t_realname]':t_realname,'User[t_email]':t_email,'User[t_mobile]':t_mobile}, success : function(data){ $('#href_data').html(data); } }); } }
註釋:三個url都是同樣的,這就是Ajax的特別之處,無論頁面數據怎麼變化,url地址仍是同樣的。
三、PHP部分。
列表-添加員工展現視圖 if(!empty($post['AddUser'])){ $Data=$this->actionTreeUpdate("",$user1->company_id,""); //獲取員工,員工詳細信息,部門實例化的model return $this->renderPartial('tree_update', [ 'model' => $Data['model'], 'model_1' => $Data['model_'], 'departar'=>$Data['departar'], 'positionar'=>$Data['positionar'], 'users' => $Data['users'], 'UId'=>'', //添加不須要傳 'UCompany_id'=>"", //添加不須要傳 'add_user'=>"add_user" ]); }
department裏的tree方法主要代碼,驗證保存數據在這裏 if(!empty($post['SEdit'])){ $UId=$post['UId']; $UCompany_id=$post['UCompany_id']; $SEdit=$post['SEdit']; $add_user=!empty($post['add_user'])?$post['add_user']:""; unset($post['SEdit'],$post['UId'],$post['UCompany_id'],$post['add_user']); $Data=$this->actionTreeUpdate($UId,$UCompany_id,$post); $class = $this->userModels; $Class_= $this->UserProfile; //判斷是否爲添加員工 if(!empty($add_user)){ $UId=0; } $model_2 = $class::findIdentity($UId); $model_3=$Class_::findOne($UId); //列表-添加員工 $t_id1=""; $t_id=!empty($model_2->attributes['t_id'])?$model_2->attributes['t_id']:""; if(empty($model_2)){ $model_2 = new $class; $post['_csrf']=Yii::$app->request->getCsrfToken(); $depart=!empty($post['department_ids'])?$post['department_ids']:array(); $model_2->parent_id=!empty($post['User']['parent_id'])?$post['User']['parent_id']:""; if($depart) { $model_2->department_id1=!empty($depart[0])?$depart[0]:0; $model_2->department_id2=!empty($depart[1])?$depart[1]:0; $model_2->department_id3=!empty($depart[2])?$depart[2]:0; $model_2->department_ids=join(',',$depart); }else{ $model_2->department_ids=""; } $model_2->t_password=base64_encode($user1->t_password); $model_2->t_state=0; $model_2->t_status=1; $model_2->company_id= $user1->company_id; if($model_2->load($post) && $model_2->save()){ //插入返回員工id $t_id1=$model_2->attributes['t_id']; $Data='success'; } } //驗證經過,選擇職位後保存 if($model_2->load($post) && $model_2->validate() && !empty($post['UserProfile']['position'])){ $Data='success'; } if($model_2->load($post) && $model_2->validate() && $Data=='success'){ if(empty($model_3) && !empty($t_id1)){ $model_3 = new $Class_; $model_3->uid=$t_id1; } //保存職位 if(!empty($post['UserProfile']['position']) && $model_3->load($post)) { $posar=!empty($post['UserProfile']['position'])?$post['UserProfile']['position']:array(); if($posar) { $model_3->position_id1=!empty($posar[0])?$posar[0]:0; $model_3->position_id2=!empty($posar[1])?$posar[1]:0; $model_3->position_id3=!empty($posar[2])?$posar[2]:0; $model_3->position_ids=$posar?join(',',$posar):''; $model_3->position=Position::getpos_name($posar); }else{ $model_3->position_id1=""; } $model_3->save(); }else{ $posar=!empty($post['UserProfile']['position'])?$post['UserProfile']['position']:array(); if(empty($posar)){ //判斷我的詳細信息表是否有值,有值直接替換,無值從新實例化 $model_3=$Class_::find()->where(['uid'=>$t_id])->one(); if(empty($model_3)){ $model_3 = new $Class_; $model_3->uid=$t_id; } $model_3->position_id1=0; $model_3->position_id2=0; $model_3->position_id3=0; $model_3->position_ids=0; $model_3->save(); } } return $this->renderPartial('tree_list', [ 'dataProvider' => $dataProvider, 'searchModel' => $searchModel, 'idField' => $this->idField, 'usernameField' => $this->usernameField, 'extraColumns' => $this->extraColumns, 'data'=>$data_1, 'data_2' => $html, 'model_'=>$model, 'department_ids1' =>!empty($Dep->id)?$Dep->id:"", 'company_id1'=>$UCompany_id, ]);
註釋:一、Yii2 Csrf自動驗證功能只有使用$model_2->validate()或者$model_2->save()纔可以觸發。
二、使用$model->load($post);$post的數組格式以下幾種類型,必須的
Array ( [User] => Array ( [parent_id] => [t_nickname] => 測試 [t_realname] => 小凌 [t_mobile] => [t_email] => 123321@qq.com ) [department_ids] => Array ( [0] => 14 [1] => 15 ) [UserProfile] => Array ( [position]=>Array ( [0] => 5 [1] => 10 ) ) [_csrf] => LkU4dlE2amdIdVI9AHVZJGYdC058BCctejRbPhdxDQJlBmI3MFkpNQ== )
一、Yii2自帶的Csrf驗證不起做用。
檢查方向:
1.一、是否使用了$model_2->validate()或者$model_2->save(),觸發Csrf驗證必須有。
1.二、Ajax傳過來的數組格式是否是正確的,上面有說明。
1.三、查看控制檯報錯信息,哪報錯從哪找緣由。
二、提交表單的時候使用submitButton,使用submitButton的話無法實現無刷新。控制器所需的數據所有都是經過JS獲取,Ajax傳的方式獲得。
三、一大模塊所有實現無刷新,有些方法代碼量會很大,得把握好它們之間的相關性和其它互不影響性。
大俠給講解一下, $model->load() 與 validate():http://www.yiichina.com/question/955
使用表單:http://www.yiibai.com/yii2/start-forms.html
Ajax+PHP實現動態無刷新技術:http://www.cnblogs.com/freespider/archive/2012/04/11/2442138.html