本文主要内容:
1, 正常情况下 cgridview 实现 ajax 分页和排序的原理
2, 分页和排序无法ajax的情况分析
3, 自定义分页(重写clinkpager)后如何实现 ajax 分页和排序
/***
author: php攻城师
http://blog.csdn.net/phpgcs
***/
[php]
widget('zii.widgets.grid.cgridview', array(
'id'=>'keyword-grid',
'dataprovider'=>$model->search(),
'cssfile'=>false,
'template'=>'{items} {pager} {summary}
',
'pager'=>array('cssfile'=>false),
'ajaxupdate'=>true,
'columns'=>array(
array(
'name'=>'leader_name',
'value'=>'$data->event',
'header'=>'关键词名称',
'headerhtmloptions'=>array('width'=>'130px'),
), .... ....
以上代码实现一个常规的 cgridview , 除了 pager 用了自定义的样式。。
而在页面的源代码中,我来找出相关的部分:
[javascript]
[javascript] view plaincopyprint?
/*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'});
});
/*]]>*/
其中会发现 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 的样子
翻页:
现在我们想要如下的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]
dataprovider->getitemcount()>0 || $this->showtableonempty)
{
$this->rendercustomerpager();
echo 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
;
$this->rendercustomerpager();
}
else
$this->renderemptytext();
}
public $paginationtop;
public $totalitemcount;
public $totalitemfoundcount;
public function rendercustomerpager()
{
$paginationtop = $this->paginationtop;
$totalitemcount = $this->totalitemcount;
$totalitemfoundcount = $this->totalitemfoundcount;
echo '';
echo '';
$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。
有更好的建议和意见,欢迎提出共同学习。
http://www.bkjia.com/phpjc/532688.htmlwww.bkjia.comtruehttp://www.bkjia.com/phpjc/532688.htmltecharticle本文主要内容: 1, 正常情况下 cgridview 实现 ajax 分页和排序的原理 2, 分页和排序无法ajax的情况分析 3, 自定义分页(重写clinkpager)后如...