本文主要內容: 1, 正常情況下 CGridView 實現 Ajax 分頁和排序的原理 2, 分頁和排序無法Ajax的情況分析 3, 自定義分頁(重寫CLinkPager)後如何實現 Ajax 分頁和排序 /*** author: php攻城師 http://blog.csdn.net/phpgcs ***/ [php] <?php $this->widget('zii.widgets.grid.CGridView', array( 'id'=>'keyword-grid', 'dataProvider'=>$model->search(), 'cssFile'=>false, 'template'=>'{items} <div class="page_area">{pager} {summary}</div>', 'pager'=>array('cssFile'=>false), 'ajaxUpdate'=>true, 'columns'=>array( array( 'name'=>'leader_name', 'value'=>'$data->event', 'header'=>'關鍵詞名稱', 'headerHtmlOptions'=>array('width'=>'130px'), ), .... .... 以上代碼實現一個常規的 CGridView , 除了 pager 用了自定義的樣式。。 而在頁面的源代碼中,我來找出相關的部分: [javascript] <script type="text/javascript" src="/chuanmei/assets/f5d36ac5/jquery.ba-bbq.js"></script> [javascript] view plaincopyprint? <script type="text/javascript" src="/chuanmei/assets/fb90bba/gridview/jquery.yiigridview.js"></script> <script type="text/javascript"> /*<![CDATA[*/ jQuery(function($) { jQuery('#keyword-grid a.delete').live('click',function() { if(!confirm('確定要刪除這條數據嗎?')) return false; var th=this; var afterDelete=function(){}; $.fn.yiiGridView.update('keyword-grid', { type:'POST', url:$(this).attr('href'), success:function(data) { $.fn.yiiGridView.update('keyword-grid'); afterDelete(th,true,data); }, error:function(XHR) { return afterDelete(th,false,XHR); } }); return false; }); jQuery('#keyword-grid').yiiGridView({'ajaxUpdate':['1','keyword-grid'],'ajaxVar':'ajax','pagerClass':'pager','loadingClass':'grid-view-loading','filterClass':'filters','tableClass':'items','selectableRows':1,'pageVar':'keyword_page'}); }); /*]]>*/ </script> 其中會發現 yii 自動加載了 jquery.ba-bbq.js && jquery.yiigridview.js ,以及2段 代碼 其中一段是用來實現 刪除 一行數據時 彈出提示框 讓用戶 確認是否刪除 功能 的; 一段是最核心關鍵的 用於 ajax update grid 的, 也正是這部分 代碼 實現了 ajax 的翻頁 和 排序。 /*********** 我是分割線 *******************************/ 如果發現 點擊了 分頁 或者 排序 後,不是ajax 方式的(也就是你可以 在 地址欄 中 看到 每次 請求的常常的 url ) 一個要檢查的地方: ajaxUpdate=>'', 這個參數 updateSelector=>'', 這個參數 /*********** 我是分割線 *******************************/ 一般情況下,CLinkPager都無法滿足我們的需求,要重寫; 而重寫我這裡提供3種方式: 1, 禁用 CGridView自己的Pager ,在 CGridView 之外 自己寫 2, 禁用 CGridView自己的Pager ,重寫 CGridView 文件, 將 自己的pager 寫在 public function renderItems() 中 3, 配置 CGridView 的 pager 參數。 如下是默認的 CLinkPager 的樣子 翻頁: < 前頁 1 2 3 後頁 > 現在我們想要如下的Pager 效果 第 31 - 40 條, 共 14546 條 上一頁 1 2 3 4 5 6 7 8 9 10 下一頁 /*** author: php攻城師 ***/ 先看第1種重寫方案: 重寫 CLinkpager 如下: [php] $this->widget('CLinkPager', array( 'header'=>'第 '.($paginationTop->getCurrentPage()*$paginationTop->getPageSize()+1). ' - '.($paginationTop->getCurrentPage()*$paginationTop->getPageSize()+$paginationTop->getPageSize()). ' 條, 共 '.$paginationTop->getItemCount().' 條 ', 'pages' => $paginationTop, 'itemCount'=>$totalItemFoundCount, 'prevPageLabel' => '上一頁', 'cssFile'=>false, 'nextPageLabel' => '下一頁', 'footer'=>' ', )); 其中的 pagination 在 controller 中生成 [php] $paginationTop = new CPagination($totalItemFoundCount); $paginationTop->pageSize= $pageSize; 然後把重寫的 CLinkPager 放在 CGridView 前面即可。 運行後發現一個Bug ,就是 分頁 不是 Ajax 的。 不是Ajax的不要緊, 關鍵是 分頁和排序不能結合使用了。 原因很簡單, 分頁不是ajax 的,而排序是ajax 的, 兩個 請求發出後 url 不在一個地方, 那麼分頁參數和 排序參數就 不再一地方, 當然無法結合使用。 解決方案: 統一起來。 要麼統一為url排序&分頁, 要麼統一為ajax排序&分頁。 url的簡單, 設置 ajaxUpdate=>false, ajax的也簡單, 只要理解了本文第一部份說的 ajax 排序的原理, 之所以不能夠 ajax 分頁, 是因為我們的分頁是 重寫了, 而且還放在了CGridView 之外, 這樣如何讓 jQuery('#keyword-grid').yiiGridView({'ajaxUpdate':['1','keyword-grid'],'ajaxVar':'ajax','pagerClass':'pager','loadingClass':'grid-view-loading','filterClass':'filters','tableClass':'items','selectableRows':1,'pageVar':'keyword_page'}); ajaxUpdate的時候 還去照顧到你寫在外面的 CLinkPager 呢? 配置2個參數: 'ajaxUpdate'=>'datalist-grid, yw0', 'updateSelector'=>'.pager a, thead th a', 本來 ajaxUpdate 的作用范圍 只是 datalist-gird , 現在我們告訴他 還要 作用在我們重寫在grid 外面的 分頁 ul ,其id 是 yw0. updateSelector 指定了 觸發 ajaxUpdate 這個動作的html元素, 也是要保證 包含了 分頁的鏈接和排序的鏈接 , 否則也是無法成功 ajax 排序/分頁。 再看第2種重寫方案: 上面第一種方案 太復雜了把, 既然問題的核心關鍵是 沒有把自定義的 ClinkPager 放在 CGridView 中, 那我們就重寫 CGridView將其放進去呗。 對,確實是可行的。 [php] <?php Yii::import('zii.widgets.grid.CGridView'); class EbuCGridView extends CGridView { /** * Renders the data items for the grid view. */ public function renderItems() { if($this->dataProvider->getItemCount()>0 || $this->showTableOnEmpty) { $this->renderCustomerPager(); echo "<table class=\"{$this->itemsCssClass}\">\n"; $this->renderTableHeader(); ob_start(); $this->renderTableBody(); $body=ob_get_clean(); $this->renderTableFooter(); echo $body; // TFOOT must appear before TBODY according to the standard. echo "</table>"; $this->renderCustomerPager(); } else $this->renderEmptyText(); } public $paginationTop; public $totalItemCount; public $totalItemFoundCount; public function renderCustomerPager() { $paginationTop = $this->paginationTop; $totalItemCount = $this->totalItemCount; $totalItemFoundCount = $this->totalItemFoundCount; echo '<div class="page_area" style="text-align:right;">'; echo '<div class="pager">'; $this->widget('CLinkPager', array( 'header'=>'第 '.($paginationTop->getCurrentPage()*$paginationTop->getPageSize()+1). ' - '.($paginationTop->getCurrentPage()*$paginationTop->getPageSize()+$paginationTop->getPageSize()). ' 條, 共 '.$paginationTop->getItemCount().' 條 ', 'pages' => $paginationTop, 'itemCount'=>$totalItemFoundCount, 'prevPageLabel' => '上一頁', 'cssFile'=>false, 'nextPageLabel' => '下一頁', 'footer'=>' ', )); .... 第3種方案: 前2種方案,說實話,都太麻煩了,破壞了yii 自身的機制, 又在其上彌補了半天。。 最好的方案 ,還是 配置 CGridView 的 'pager' ,來實現我們要更復雜的CLinkPager的目標。 但是,有些時候還真必須用第 1、2種方案; 比如我應用的情況是: 用 Coreseek 全文索引 查詢出 數據 的id ,再 用 id 來到數據庫中找出數據,形成 CActiveDataProvider ,最後用 CGridView來展示。 我這裡的 CDbCriteria 如下 [php] $criteria = new CDbCriteria; $criteria->join = 'LEFT JOIN site2 AS si** ON t.**=**.domain_hash'; $criteria->addInCondition('t.id', $IDARRAY); $criteria->select = array("t.id", "t.content", "t.pubtime", "t.url", "t.reply_num", "t.retweet_num", "site_config.site_name"); $criteria->order = 'FIND_IN_SET(t.id, "'.join(",", $IDARRAY).'")'; 其中 變量 IDARRAY 正是 coreseek 得到的 一個 id 組成的數組 如果按照 普通的 [php] $dataProvider = new CActiveDataProvider('TData', array( 'criteria'=>$criteria, 'pagination'=>array( 'pageSize'=>10, ), )); 是不滿足我的需求的。 因為我的分頁和排序都是在 coreseek 中完成的, 這裡用 CActiveDataProvider 只是提供了當前頁(比如每一頁10條記錄)的10條記錄。 end。 有更好的建議和意見,歡迎提出共同學習。