使用PHP和jQuery制作分页和表格

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

使用PHP和jQuery制作分页和表格
如果您已经下载了本站提供的baseProject项目源码,后台中列表页面均可作为示例,其中文章列表页面的功能最为丰富。

如果您没有下载该源码,相关的js文件可以从
/scripts/basic.js获得,示例页面为/feedback 页面。

以下是后台文章列表页面的截图。

分页和表格功能实例截图
分页功能详解
分页功能用于当目标数据过多时,为提高页面展示速度采用的一种手段。

本文中的分页功能借用了Zend Framework中的Zend_Paginator对象,分页适配器为
Zend_Paginator_Adapter_Null。

该适配器也是最简单易用的一个。

工作原理
在PHP端,分页功能的基本参数为记录总数($countRows)、每页显示的记录数($rowsPerPage)、当前页码($page 默认值为1),页码数量($items 指每次在页面上显示多少个页码,建议为单数)。

其他参数可以通过计算得到:
1.页码合计($countPages)取不小于$countRows/$rowsPerPage的整数;
2.起始页码和结束页码的计算方式太长不写了;
3.页码列表:从起始页码到结束页码的页码组成的数组,如array(4, 5, 6, 7, 8)
在HTML端,必要的参数为PHP端计算得出的数据,同时需要指定一个用于显示分页信息的html元素。

然后使用jQuery根据参数动态生成html并将其插入到指定的html元素中就行了。

PHP示例代码详解
1.public function articlesAction() {
2.$pageNumber= $this->getRequest()->getParam('page', 1);//获取当前页码,
如果未指定则设为1
3.$sortBy= $this->getRequest()->getParam('sortby');//获取sortby设置
4.if (empty($sortBy) || ! preg_match('/^[a-z0-9_-]+ (asc|desc)$/i', $sortBy)) {
5.//如果sortBy为空或者不符合格式要求则使用以下的排序方式
6.//注意:一定要进行格式检查,防止sql注入
7.$sortBy= Project_Table::getFullyColumnName('article', 'id') . ' desc';
8.}
9.$mArticle= new Model_Article();
10./* 这部分是处理where子句的,和本文关系不大,略过*/
11.$whereArray = array(
12.'`article`.`article_category_id`'
=>$this->getRequest()->getParam(Project_Table::getFullyColumnName('article',
'article_category_id')),
13.'`article`.`article_status_id`'
=>$this->getRequest()->getParam(Project_Table::getFullyColumnName('article',
'article_status_id')),
14.);
15.$whereString = '';
16.foreach ($whereArray as $key => $value) {
17.if (! empty($value)) {
18.if ($key == '`article`.`article_category_id`' &&$value == '-1') {
19.$whereString .= " AND {$key} IS NULL";
20.} else {
21.$whereString .= " AND {$key} = '{$value}'";
22.}
23.}
24.}
25.if (! empty($whereString)) {
26.$whereString= substr($whereString, strlen(' AND '));
27.} else {
28.$whereString = null;
29.}
30./* 以上是处理where子句的*/
31.$maxGetRows= Project_Config::PAGINATOR_ITEM_COUNT_PER_PAGE;//设置
每页显示的记录数量
32.$articles = $mArticle->getArticles($whereString, $sortBy, $maxGetRows,
($pageNumber - 1) * $maxGetRows);//从数据库中读取数据
33.$countArticles= Project_Table::getLastFoundRows();//获得符合条件的数据
总数
34.if (empty($articles) && ! empty($countArticles)) {
35.//如果没有取到任何记录,而且记录总数不为空,说明当前页码超出范围了,所以处理一下
36.$articles = $mArticle->getArticles($whereString, $sortBy, $maxGetRows, null);
37.$pageNumber = 1;
38.}
39.$pDate= Project_Datetime::getInstance();//时间处理工具,和本文无关
40.foreach ($articles as $key => $article) {
41.$articles[$key][Project_Table::getFullyColumnName('article', 'modified')] = $pDate->getUserTimeFromTime($article[Project_Table::getFullyColumnName('article',
'modified')], true);//把时间戳转换为用户的当地时间,和本文无关
42.}
43.$paginator= Zend_Paginator::factory($countArticles, 'Null');//调用Zend提供的分页适配器,参数1是总记录数,参数2是适配器的名字
44.$paginator->setCurrentPageNumber($pageNumber);//告诉分页器当前页码
45.$pages = $paginator->getPages();//得到了前面提到的所有参数,后面我会打印它,这样你会直观的看到其内容
46.$this->view->articles = $articles;
47.$this->view->pages = $pages;
48.//以下处理是为了页面中的下拉选单提供选项数据,和本文关系不大
49.if(! $this->getRequest()->isPost()) {
50.$mpArticle= new Mapper_Article();
51.$this->view->elementArticleStatusId =
$mpArticle->getElement('article_status_id', array(Project_Mapper::OPTIONS_NULLABLE =>true, Project_Mapper::OPTIONS_DEFAULT =>''));
52.$_categories = $mArticle->getAllowAppendArticleArticleCategories(null, null, null, null, true);
53.$categories = array(
54.$this->view->translate(Model_Article::NO_CATEGORY) =>'-1',
55.);
56.foreach ($_categories as $key => $row) {
57.
$categories[$row[Project_Table::getFullyColumnName('article_category', 'name')]] = $row[Project_Table::getFullyColumnName('article_category', 'id')];
58.}
59.$mpArticle= new Mapper_Article();
60.$this->view->elementArticleCategories =
$mpArticle->getElement('article_category_id', array(Project_Mapper::OPTIONS_IN_ARRAY =>$categories, Project_Mapper::OPTIONS_NULLABLE =>true));
61.}
62.}
$pages中的内容我打印了一下,这样更直观。

如下。

63.stdClass Object
64.(
65.[pageCount] => 3
66.[itemCountPerPage] => 10
67.[first] => 1
68.[current] => 2
69.[last] => 3
70.[previous] => 1
71.[next] => 3
72.[pagesInRange] => Array
73.(
74.[1] => 1
75.[2] => 2
76.[3] => 3
77.)
78.
79.[firstPageInRange] => 1
80.[lastPageInRange] => 3
81.[currentItemCount] => 10
82.[totalItemCount] => 21
83.[firstItemNumber] => 11
84.[lastItemNumber] => 20
85.)
Zend Framework的开发人员确实很认真,返回的参数非常充分,不需要任何的补充。

顺便提一下以上代码中未体现的细节,当使用post方式访问该页面时会得到json数据而不是html。

这个细节写在init()方法中,代码如下:
1.public function init() {
2.if ($this->getRequest()->isPost()) {
3.$this->_helper
4.->contextSwitch()
5.->addActionContext('articles', 'json') //就是这里咯
6.->addActionContext('trashcategory', 'json')
7.->addActionContext('trasharticle', 'json')
8.->addActionContext('movecategory', 'json')
9.->initContext('json');
10.}
11.}
HTML示例代码详解
这次只贴出关键的内容哦。

1.<form method="POST" action="<?php echo $this->url()?>" onsubmit="
2.try{
3.return pBase.submitForm(this, true, null, loadArticlesGrid);//使用ajax提交表单,回调函数为loadArticlesGrid
4.} catch(e) {
5.alert(e.message);
6.return false;
7.};">
8.<div class="beforeGridclearFloat">
9.<div class="floatLeft">
10.<!--Pagination是我写的helper,关于这个东西后面解释-->
11.<?php echo $this->pagination($this->pages->current, 'articles')?>
12.</div>
13.<!--截图中右侧的文档选择器-->
14.<div class="floatRight">
15.<?php echo $this->search_select($this->elementArticleStatusId, array('onchange' =>"pBase.paginator('div.pagination[name=articles]', 'goto', 1);"));?>
16.<?php echo $this->search_select($this->elementArticleCategories, array('onchange' =>"pBase.paginator('div.pagination[name=articles]', 'goto', 1);"));?>
17.<?php echo $this->iconButton('add',
$this->actionTitle('createarticle'), "window.open('{$this->url(array('action'
=>'editarticle'))}')", ! Project_Session::getInstance()->isAllow('editarticle'))?>
18.</div>
19.</div>
20.<!--这是表格部分,先不说它-->
21.<table id="articleGridTable" class="gridTable">…</table>
22.<!--底部的分页栏-->
23.<div class="afterGridclearFloat">
24.<div class="floatLeft">
25.<?php echo $this->pagination($this->pages->current, 'articles', false)?>
26.</div>
27.</div>
28.</form>
29.<script type="text/javascript">
30.$(document).ready(function(){
31.//这句话就是调用js绘制分页的,第一个参数是目标容器,第二个参数是相关参数组成的json对象(就是json_encode($pages)啦)
32.pBase.paginator('div.pagination[name=articles]', {$jsonPages});
33.});
34.function loadArticlesGrid(response) {
35.//ajax回调,此时重绘分页
36.pBase.paginator('div.pagination[name=articles]', response.pages);
37.}
38.</script>
里面用到了一个helper,因为这样可以避免反复去写类似的html内容。

带有两个参数,
第一个是当前的页码,第二个用于控制是否输出表单元素(默认为true,输出)。

当第二个参数为默认值true时,其输出如下:
1.<inputtype="hidden" name="page" value="2" /><inputtype="hidden" name="sortby"
value="" /><divclass="pagination clearFloat" name="articles"></div>
为false时其输出为:
1.<divclass="pagination clearFloat" name="articles"></div>
对于参数为true的输出,您可能会问为什么sortby没有初始值?确实没想过,我也不希望用户在url中手动添加sortby参数。

Javascript代码说明
具体的代码很长,就不贴出来了,可以自行查看,仅列举配置信息和例子。

1.var _configs = {
2.boxClass: 'pagination',//分页的总体样式名称
3.firstClass: 'first',//首页所使用的样式名称
4.firstText: false,//首页使用的文本,false表示使用数字
stClass: 'last',//尾页所使用的样式名称
stText: false,//尾页使用的文本,false表示使用数字
7.previousClass: 'previous',//上一页使用的样式名称
8.previousText: '<',//上一页所使用的文本
9.nextClass: 'next',//下一页所使用的样式名称
10.nextText: '>',//下一页所使用的文本
11.pageClass: 'page',//每个页面元素所使用的样式名称
12.currentPageClass: 'current',//当前页所使用的样式名称
13.pagesElementClass: 'pages',//所有页码的公共父节点使用的样式名称
ElementClass: 'info',//信息节点的公共父节点使用的样式名称
ElementCountPageClass: 'countPage',//总页数信息的样式名称
ElementCurrentPageClass: 'current',//当前页信息的样式名称
ElementCountItemsClass: 'countItems',//总条目数量信息的样式名称
ElementPageItemsClass: 'pageItems',//页内条目数量信息的样式名称
ElementFirstItemClass: 'first',//本页内第一个条目的序号信息的样式名

ElementLastItemClass: 'last',//本页内最后一个条目的序号信息的样式
名称
21.ajaxBoxClass: 'ajaxBox',//ajax读取状态容器的样式名称
22.ajaxLoader: function() {
23.return $('<div class="ajaxLoader16"></div>');
24.},//获取一个ajax读取中的html
25.pageCount: 0,//总页数
26.itemCountPerPage: 0,//页内最大条目数
27.totalItemCount: 0,//总条目数
28.pagesInRange: [],//页码列表
29.firstPageInRange: false,//页码列表中的第一个页码
stPageInRange: false,//页码列表中的最后一个页码
31.currentItemCount: 0,//本页条目数
32.firstItemNumber: 1,//第一条的序号
stItemNumber: 1,//最后一条的序号
34.previous: false,//上一页的页码
35.first: false,//第一页的页码
st: false,//最后一页的页码
37.current: 1,//当前页的页码
38.next: false,//下一页的页码
39.referenceForm: 'form:first',//引用的表单
40.referencePageItem: 'page'//表单中表示页码的表单元素名称
41.};
功能原型:pBase.paginator(string|HtmlElement selector, jsonObject|stringconfigs[, number])
参数说明:
selector: 选择器,分页的Html内容将注入到该选择器指定的元素。

configs: 配置信息,如果是对象,那么利用该对象声明的参数重绘分页(此时忽略第三个参数number),如果是字符串,字符串应为removeItem, addItem或者goto之一。

number: 在configs为字符串时需要该参数。

说明如下:
configs为removeItem: number表示当前页内有多少行已经删除;
configs为addItem: number表示当前页内新增了多少行;
configs为goto: number表示目标页码;
分别示例如下。

1.pBase.paginator(‘#pager’, {}); //在$(‘#pager’)内显示分页信息
2.pBase.paginator(‘#pager’, ‘removeItem’, 1); //页内条目数及总条目数-1
3.pBase.paginator(‘#pager’, ‘addItem’, 1); //页内条目数及总条目数+1
4.pBase.paginator(‘#pager’, ‘goto’, 5); //跳转到第5页
表格功能详解
其实就是Grid这个东西咯,设计目标是使用表格的方式展示数据,同时支持动态更新、插入和删除行。

表格部分的完整功能截图如下,该截图来自baseProject项目后台的地理信息管理部分(文章管理部分的编辑功能没有使用表格自带的编辑逻辑)。

表格实例截图(行内编辑窗口已弹出)
设计思路
数据源应该是json格式的二维数组。

表格分为thead和tbody两部分。

我的想法就是在thead中的首行使用属性的方式描述对应的列中的数据的显示逻辑和样式信息,从而实现基于jQuery自动填充表格数据。

HTML源码示例
1.<table id="articleGridTable" class="gridTable">
2.<thead>
3.<tr row_id="<?php echo Project_Table::getFullyColumnName('article', 'id')?>"
row_name="<?php echo Project_Table::getFullyColumnName('article', 'title')?>">
4.<th class="desc" column="<?php echo
Project_Table::getFullyColumnName('article', 'id')?>" td_class="alignRight"><?php echo
$this->column_name('article', 'id')?></th>
5.<th column="getRowDataOfLanguage" sortby="<?php echo
Project_Table::getFullyColumnName('article', 'language')?>"><?php echo
$this->column_name('article', 'language')?></th>
6.<th column="<?php echo Project_Table::getFullyColumnName('article',
'title')?>"><?php echo $this->column_name('article', 'title')?></th>
7.<th class="unsortable"
column="getRowDataOfCategoryName"><?php echo
$this->column_name('article_category', 'name')?></th>
8.<th column="<?php echo Project_Table::getFullyColumnName('user',
'screen_name')?>"><?php echo $this->column_name('article', 'create_by_user_id')?></th>
9.<th column="getRowDataOfArticleStatus" sortby="<?php echo
Project_Table::getFullyColumnName('article_status', 'name')?>"
td_class="alignCenter"><?php echo $this->column_name('article',
'article_status_id')?></th>
10.<th column="<?php echo Project_Table::getFullyColumnName('article',
'modified')?>" td_class="alignCenter"><?php echo $this->column_name('article',
'modified')?></th>
11.<th class="unsortable" column="getRowActions"
td_class="clearFloatalignCenter" style="width: 60px;"></th>
12.</tr>
13.</thead>
14.<tbody>
15.</tbody>
16.</table>
在tr中,使用了自定义属性row_id和row_name,row_id是用于标识行内数据的主键
的值,row_name则是标识行内数据的友好名称,通常用于删除前的确认时能够弹出更友好的信息,如“您是否确认删除文档欢迎光临本站?”
对于每一个th,自定义属性包括column,sortby和td_class。

column属性用于指明如何显示该列的数据,sortby属性用于指明当用户要求对该字段排序时使用哪个字段排序(可选),td_class用于指明改列使用的样式class名称。

th本身的class可以是desc(标识当前列降序),asc(标识当前列为升序),sortable(标识当前列可以被排序,当标识为可排序时,如果column 属性的值是字段名,那么可以省略sortby属性,否则sortby属性是必需的)或unsortable(标识当前列不能被排序,如不能排序则会忽视sortby属性的检查)
tr的row_name属性和th的column属性的值可以是字段名,也可以是javascript函数名。

当为函数名时,其值为该函数的返回值。

调用该函数时传入的参数为当前的数据行。

例如json 数据为varjsonData = [{name: ‘Nick’}];,column指定为column=”getNameColumnString”,那么程序会尝试调用
1.for(vari = 0; i<jsonData.length; i++) td.html(getNameColumnString(jsonData[i]));
JS部分源码说明
源码很长,同样只说明配置信息部分,以及应用举例。

1.var _configs = {
2.attributeRowId: 'row_id',//thead>tr声明每行的主键信息时使用的属性名称
3.attributeRowName: 'row_name',//thead>tr声明每行的名称的使用的属性名称
4.rowDataColumn: 'column', //thead>tr>td声明字段数据使用的属性名称
5.rowDataSortByColumn: 'sortby', //thead>tr>td声明排序字段使用的属性名称
6.rowColumnClass: 'td_class', //thead>tr>td声明数据列样式类使用的属性名称
7.rowColumnDescClass: 'desc', //thead>tr>td声明数据列降序排序时的样式类
8.rowColumnAscClass: 'asc', //thead>tr>td声明数据列升序排序时的样式类
9.rowColumnSortableClass: 'sortable', //thead>tr>td声明数据列未排序时的样式类
10.rowColumnDisableSortableClass: 'unsortable', //thead>tr>td声明数据列不能排序时的样式

11.rowAction: false,//tbody>tr被点击时触发的行为
12.autoDisableEventBubbling: true, //自动阻止tbody>tr>td中的鼠标事件冒泡
13.defaultRowClass: false, //默认的tbody>tr样式类
14.evenRowClass: 'even', //tbody中的偶数行的样式类
15.referenceForm: 'form:first', //排序时触发提交的表单
16.referenceSortbyItem: 'sortby', //保存排序参数的表单元素名称
17.referencePageItem: 'page', //保存页码参数的表单元素名称
18.sortable: false, //允许排序
19.paginatorSelector: false, //关联的分页器的元素选择器
20.dialogOverflowY: 'hidden'//当弹出编辑对话框时,如果内容超出对话框高度如何处理
21.};
应用原型说明:
pBase.grid(jQuery选择器(建议为id) table, JSON|HtmlElement data,
jsonObject|stringconfigs[, string url])
table为jQuery选择器,指明目标表格;
data为json数据,可能是{}格式或[{}]格式的json数据、HtmlElement元素或null,视configs 的值而定;
configs为{}格式的json数据或字符串,字符串取值范围为trash, edit, remove, update, reset, even之一;
url:当configs取值为trash或edit时需要指定该参数,值为url地址,当请求该地址时会自动追加参数id/当前行的id,请注意不要冲突。

Configs为trash时会发送POST请求,否则会发送GET请求;
应用示例说明:
1.pBase.grid(‘#results’, [{id:1, name:’nick’}], {sortable: true}); //初始化,并将数据显示到表格
#results
2.pBase.grid(‘#results’, [{id:1, name:’nick’}], ‘reset’); //使用指定的数据重绘tbody区域
3.pBase.grid(‘#results’, $(‘#results tbodytr:firsttd:lastbutton:first’), ‘edit’, ‘edit.php’); //第二个
参数表示行中的一个操作按钮,程序会尝试获取该元素的父级中的第一个tr并取得行的编号,然后发送给指定的地址,并将返回的内容显示在对话框中
4.pBase.grid(‘#results’, $(‘#results tbodytr:firsttd:lastbutton:eq(1)’), ‘trash’, ‘trash.php’);//第二
个参数表示行中的一个操作按钮,程序会尝试获取该元素的父级中的第一个tr并取得行的编号,然后发送给指定的地址,并自动调用pBase.grid(‘#results’, ajaxResponseJson, ‘remove’)处理返回的结果。

关于ajaxResponseJson的格式要求见后文。

5.pBase.grid(‘#results’, ajaxResponseJson, ‘update’); //根据ajaxResponseJson的值尝试
update相应的行,关于ajaxResponseJson的格式要求见后文。

6.pBase.grid(‘#results’, ajaxResponseJson, ‘remove’); //根据ajaxResponseJson的值尝试
remove相应的行,关于ajaxResponseJson的格式要求见后文。

7.pBase.grid(‘#results’, null, ‘even’); //重置偶数行标记
关于ajaxResponseJson的说明:
对于update,要求ajaxResponseJson包括以下的内容:
如果ajaxResponseJson不是json格式,那么会在弹出的对话框中显示该内容(如果该对话框是由grid的edit行为生成的话,否则什么都不会发生。

也就是说,如果您是独立的使用该方法时,应该先确认返回值是json数据才能将其传入pBase.grid)。

否则应形如以下代码:{success: true/false, message: ‘null|string’, row: {…}}。

如果未提供success参数则认为success为true,如果success为true而未提供message,那么message 则被认为是’Update Success’的翻译结果。

当success为true时,row是必须的,是被编辑的行的json数据,如{id:1, name:’nick’}。

程序会尝试在当前表格的tbody区域中寻找主键一致的行,如果找不到则在顶部新增一行,否则更新它。

对于remove,要求ajaxResponseJson必须是json数据,否则不会处理,其格式应形如
{success: true/false, rowId: ‘id’}。

success是必须的,如果不是true则认为删除失败。

rowId是被删除数据的主键值,程序会在当前表格的tbody区域中寻找主键一致的行并删除它(如果success为true的话)。

分页和表格功能的联合应用
在初始化表格时,通过参数paginatorSelector可以将表格与分页器关联,例如
1.pBase.grid('#articleGridTable', jsonArticles, {sortable: true, paginatorSelector:
'div.pagination[name=articles]'});
当使用表格的update或remove功能增加/删除行成功时,分页器内的数据会相应变化。

当表格提交排序申请时,页码也会重置为第一页。

baseProject项目源码中后台的地理信息管理等页面均使用了该方法。

相关文档
最新文档