本文主要內容:
1, 正常情況下 CGridView 實現 Ajax 分頁和排序的原理
2, 分頁和排序無法Ajax的情況分析
3, 自定義分頁(重寫CLinkPager)後如何實現 Ajax 分頁和排序
/***
author: php攻城師
http://blog.csdn.net/phpgcs
***/
/*********** 我是分割線 *******************************/
<?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 用了自定義的樣式。。
而在頁面的源代碼中,我來找出相關的部分:
<script type="text/javascript" src="/chuanmei/assets/f5d36ac5/jquery.ba-bbq.js"></script>
<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>
其中一段是用來實現 刪除 一行數據時 彈出提示框 讓用戶 確認是否刪除 功能 的;
一段是最核心關鍵的 用於 ajax update grid 的, 也正是這部分 代碼 實現了 ajax 的翻頁 和 排序。
/*********** 我是分割線 *******************************/
一個要檢查的地方:
ajaxUpdate=>'', 這個參數
updateSelector=>'', 這個參數
/*********** 我是分割線 *******************************/
一般情況下,CLinkPager都無法滿足我們的需求,要重寫;
而重寫我這裏提供3種方式:
1, 禁用 CGridView自己的Pager ,在 CGridView 之外 自己寫
2, 禁用 CGridView自己的Pager ,重寫 CGridView 文件, 將 自己的pager 寫在 public function renderItems() 中
3, 配置 CGridView 的 pager 參數。
如下是默認的 CLinkPager 的樣子
翻頁:
現在我們想要如下的Pager 效果
第 31 - 40 條, 共 14546 條
/***
author: php攻城師
http://blog.csdn.net/phpgcs
***/
先看第1種重寫方案:
重寫 CLinkpager 如下:
$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 中生成
$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
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'=>' ',
));
....
前2種方案,說實話,都太麻煩了,破壞了yii 自身的機制, 又在其上彌補了半天。。
最好的方案 ,還是 配置 CGridView 的 'pager' ,來實現我們要更復雜的CLinkPager的目標。
但是,有些時候還真必須用第 1、2種方案;
比如我應用的情況是:
用 Coreseek 全文索引 查詢出 數據 的id ,再 用 id 來到數據庫中找出數據,形成 CActiveDataProvider ,最後用 CGridView來展示。
我這裏的 CDbCriteria 如下
$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 組成的數組
如果按照 普通的
$dataProvider = new CActiveDataProvider('TData', array(
'criteria'=>$criteria,
'pagination'=>array(
'pageSize'=>10,
),
));
因爲我的分頁和排序都是在 coreseek 中完成的, 這裏用 CActiveDataProvider 只是提供了當前頁(比如每一頁10條記錄)的10條記錄。
end。
有更好的建議和意見,歡迎提出共同學習。