之前写了一个简单的Angularjs的分页指令,在后期工作量减少后对分页做了一些优化,将分页数据的查询及页码跳转都写在了指令内部,减少了controller中的代码量,使用更加简单。
指令定义
定义指令的module中糅合了指令的定义及查询数据的factory,将页码跳转的方法写在了指令中,指令使用的模板和factory中的查询方法都没有变化,只是factory的位置及使用方式发生了一些变化,具体看代码:
'use strict';
(function () {
var forEach = angular.forEach;
angular.module('template/pageInit/pageInit.html', []).run([
'$templateCache',function($templateCache) {
$templateCache.put('template/pageInit/pageInit.html',
'<ul class="pagination-main">\n'+
' <li class="prev-page" ng-class="{disabled:pageData.currentPage==1}" title="首页">\n'+
' <a href="javascript:void(0);" ng-click="on_loadPage(1)"><span class="fa fa-fast-backward"></span></a>\n'+
' </li>\n'+
' <li class="prev-page" ng-class="{disabled:pageData.currentPage==1 }">\n'+
' <a href="javascript:void(0);" ng-click="on_prev()" title="上一页"><span class="fa fa-step-backward"></span></a>\n'+
' </li>\n'+
' <li class="data-page" ng-repeat="page in pageData.pages" ng-class="{\'first-page\': page==1, \'last-page\': page==pageData.totalPage}">\n'+
' <a ng-if="page!=\'...\'" href="javascript:void(0);" ng-class="{\'bg-custom\': page==pageData.currentPage}" ng-click="on_loadPage(page, tabData)">{{ page }}</a>\n'+
' <a ng-if="page==\'...\'" href="javascript:void(0);" ng-class="{\'bg-custom\': page==pageData.currentPage}" ng-click="">{{ page }}</a>\n'+
' </li>\n'+
' <li class="next-page" ng-class="{disabled:pageData.currentPage==pageData.totalPage}">\n'+
' <a href="javascript:void(0);" ng-click="on_next()" title="下一页"><span class="fa fa-step-forward"></span></a>\n'+
' </li>\n'+
' <li class="skip-page"><div><input type="text" placeholder="" ng-model="inpage">\n'+
' <input type="button" value="跳转" ng-click="on_loadPage(inpage)"></div>\n'+
' </li>\n'+
' <li class="data-num"><a class="cursor-text" href="#"><span>共{{pageData.count}}条</span></a></li>\n'+
'</ul>\n'+
''
);
}
]);
angular.module('pageInit2', ['template/pageInit/pageInit.html'])
.factory('PageSync', ['$http', '$q', function Page($http, $q) {
var rowCollectionPage = [];
var totalPage = 1;
var pages = [];
var endPage = 1;
var load = function(url, currentPage, pageSize,deferred) {
var json = {rowCollectionPage: [], totalPage: 1, currentPage:currentPage ? currentPage:1, pages: []};
$http.get(url).success(function(rows) {
rowCollectionPage = setPageRow(rows.list, pageSize);
// 获取总页数
totalPage = Math.ceil(rows.count / pageSize);
endPage = totalPage;
// 生成数字链接
if (totalPage <= 7) {
pages = getPagesLow(totalPage);
} else {
pages = getPagesHigh(currentPage, totalPage);
}
/*if(totalPage <= 1) {// 总页数就一页的时候这里放入一个空对象代替的是分页那一行
rowCollectionPage.push({});
}*/
json.rowCollectionPage = rowCollectionPage;
json.totalPage = totalPage==0 ? 1 : totalPage;
json.currentPage = currentPage;
json.pages = pages;
json.count = rows.count;
json.pageSize = pageSize;
/**
* 自定义字段,初始化的时候为before,只要经过该分页方法,则字段值变为after
* before表示未经过该分页方法,after表示经过该分页方法,
* 前台页面加载的规则:为before时表示表格无数据,为after且pataData.count==0时无数据,否则视为有数据
*/
json.loadTime = 'after';
deferred.resolve(json);
});
return deferred.promise;
};
// 总页数小于等于7时 显示所有的页数
var getPagesLow = function(totalPage) {
var temp = [];
for (var i=1; i<totalPage+1; i++) {
temp.push(i);
}
return temp;
};
// 总页数大于7时 根据当前页获取7个页码数
var getPagesHigh = function(currentPage, totalPage) {
var temp = [];
if (currentPage < 4) {
temp = [1, 2, 3, 4, 5, '...', totalPage];
} else if ((totalPage - currentPage) <= 3) {
temp = [
totalPage - 6, totalPage - 5, totalPage - 4,
totalPage - 3, totalPage - 2, totalPage - 1, totalPage
];
} else {
temp = [
currentPage - 2, currentPage - 1, currentPage,
currentPage + 1, currentPage + 2, '...', totalPage
];
}
return temp;
};
var setPageRow = function(rowArr, pageSize) {
var temp = [];
if (rowArr != undefined) {
for (var i = 0; i < rowArr.length; i++) {
temp.push(rowArr[i]);
}
for (var j = 0; j < pageSize - rowArr.length; j++) {
temp.push({});
}
} else {
for (var k = 0; k < pageSize; k++) {
temp.push({});
}
}
return temp;
};
return {
load: function(url, currentPage, pageSize) {
var deferred = $q.defer();
url += '&' + currentPage + '&' + pageSize;
return load(url, currentPage, pageSize, deferred);
},
next: function(url, currentPage, pageSize) {
var deferred = $q.defer();
if (currentPage < endPage) {
currentPage++;
}
url += '&' + currentPage + '&' + pageSize;
return load(url, currentPage, pageSize, deferred);
},
prev: function(url, currentPage, pageSize) {
var deferred = $q.defer();
currentPage--;
url += '&' + currentPage + '&' + pageSize;
return load(url, currentPage, pageSize, deferred);
},
loadPage: function(url, currentPage, pageSize, page) {
var deferred = $q.defer();
if (currentPage != page) {
currentPage = page;
url += '&' + currentPage + '&' + pageSize;
return load(url, currentPage, pageSize, deferred);
}
}
}
}])
.directive('pageInits', ['pageinitTemplate', 'PageSync', '$rootScope', function(pageinitTemplate, PageSync, $rootScope) {
return {
restrict : 'AE',
templateUrl: function (tElement, tAttrs) {
return tAttrs.templateUrl || pageinitTemplate.getPath();
},
replace : true,
scope : {
queryUrl : '=queryUrl',
condition : '=condition',
pageData : '=pageData',
pageSize : '=pageSize'
},
link : function(scope, element, attrs) {
scope.arr = [];// 存放需要监控属性值变化的变量,根据是否变化进行查询分页数据与否
scope.valArr = [];// 存放查询条件变量值
// 分页时无数据用空行代替,使分页始终在页面底部
var setPageRow = function(rowArr, pageSize) {
var temp = [];
if (rowArr != undefined) {
for(var i=0; i<rowArr.length; i++) {
temp.push(rowArr[i]);
}
if (rowArr.length < pageSize) {
for(var j=0; j<pageSize-rowArr.length; j++) {
temp.push({});
}
}
}
return temp;
};
// 获取分页的url
var initUrl = function() {
var result = scope.queryUrl;
var condArr = scope.valArr;
for(var i = 0; i < condArr.length; i++) {
if(i == 0) {
result += condArr[i];
} else {
result += '&' + condArr[i];
}
}
return result;
};
var url = '';
// 查询数据
var load = function() {
var pageSize = scope.pageData.pageSize = scope.pageSize ? scope.pageSize : 10;
scope.pageData.rowCollectionPage = setPageRow([],pageSize);
scope.pageData.noTableData = false;
scope.pageData.loadTime = 'before';
PageSync.load(url, scope.pageData.currentPage, pageSize).then(function(data) {
scope.pageData = data;
if((scope.pageData.loadTime=='after'&& scope.pageData.count==0) || scope.pageData.loadTime=='before') {
scope.pageData.noTableData = true;
}
});
};
// 循环拿到分页的查询条件
for(var key in scope.condition) {
scope.arr.push('condition.'+key);
}
scope.arr.push('pageData.loadTime');
// 监控分页的查询条件,并得到分页查询条件所对应的值
scope.$watchGroup(scope.arr, function(newVal) {
if(newVal[newVal.length-1] != 'after') {
scope.valArr = [];
forEach(newVal, function(val, index) {
if(index != newVal.length-1) {
scope.valArr.push(val);
}
});
url = initUrl();
load(scope);
}
});
// 上一页
scope.on_prev = function() {
if (scope.pageData.currentPage > 1) {
PageSync.prev(url, scope.pageData.currentPage, scope.pageSize).then(function (data) {
scope.pageData = data;
});
}
};
// 下一页
scope.on_next = function() {
if (scope.pageData.currentPage < scope.pageData.totalPage) {
PageSync.next(url, scope.pageData.currentPage, scope.pageSize).then(function(data) {
scope.pageData = data;
});
}
};
// 跳转
scope.on_loadPage = function(page) {
scope.inpage = undefined;
var intPage;
if (typeof page == 'string') {
if(page!="") {
intPage = parseInt(page, 10);
} else {
intPage = 0;
}
} else {
intPage = page;
}
if (scope.pageData.totalPage <= 1) {
} else if (intPage == undefined || intPage == null) {
$rootScope.lxAlert['danger']('请填写跳转页码!');
} else if(intPage <= 0 || intPage > scope.pageData.totalPage) {
$rootScope.lxAlert['danger']('跳转页码应大于0,小于总页数'+scope.pageData.totalPage);
} else if (scope.pageData.currentPage != page) {
PageSync.loadPage(url, scope.pageData.currentPage, scope.pageSize, page).then(function (data) {
scope.pageData = data;
});
}
};
}
};
}])
.provider('pageinitTemplate', function () {
var templatePath = 'template/pageInit/pageInit.html';
this.setPath = function (path) {
templatePath = path;
};
this.$get = function () {
return {
getPath: function () {
return templatePath;
}
};
};
});
}).call(window);
分页样式控制
参考我的另一篇文章Angularjs分页指令,样式一样。
使用指令
页面上的代码
<table>
<thead>
<tr>
<th>序号</th>
<th>列名1</th>
<th>列名2</th>
<th style="width: 150px;text-align: center;">操作</th>
</tr>
</thead>
<tbody>
<tr ng-if="!pageData.noTableData" ng-repeat="row in pageData.rowCollectionPage">
<td>{{!!row.id ? $index+1+(pageData.currentPage-1)*pageSize : ''}}</td>
<td>{{row.args1}}</td>
<td>{{row.args2}}</td>
<td style="text-align: center;"><a href='#'>修改</a></td>
</tr>
<tr ng-if="pageData.noTableData" ng-repeat="data in pageData.rowCollectionPage">
<td ng-if="$index == 0" colspan="4" style="text-align: center;">没有数据!</td>
<td ng-if="$index != 0" colspan="4"></td>
</tr>
</tbody>
<tfoot>
<tr>
<td style="text-align: center;" colspan="6">
<div>
<page-inits query-url="queryUrl" condition="condition" page-data="pageData" page-size="pageSize"></page-inits>
</div>
</td>
</tr>
</tfoot>
</table>
与上一篇的变化:该指令定义是将noTableData写在了pageData中,是pageData的一个元素,页面上与之相应的改变成pageData.noTableData(noTableData用来判断当前页是否存在数据);分页名称改变成pageInits,页面上指令的使用与之相应改变。
controller中的代码
这里不需要再引用PageSync(factory),是在定义指令时引用的,且factory写在了指令所在的module中。
使用指令时controller中不需要再写分页查询及跳转的方法,但必须把分页所需的项全部配置对才可正确的进行分页(目前做的兼容性可能会很差,配置不对会报错或不执行查询分页)。
$scope.height = Common.getWindowsHeight();
// 初始化分页信息
$scope.pageData = {rowCollectionPage: [], totalPage: 1, currentPage:1, pages: [],count: 0, loadTime: 'before',noTableData: false};
// 计算每页的行数
$scope.tabHeight = $scope.height-48-37-10-42-5;
$scope.pageSize = parseInt(($scope.tabHeight-15-34-39)/34);
// 查询路由接口(不带参数,具体的需要在指令中根据特定规则生成)
$scope.queryUrl = '/api/disease/getPageData/';
// 监控查询条件:对中文查询条件做了encode操作,防止到后台乱码,后台再做uncode操作即可。
$scope.$watch('name', function() {
if($scope.name== '') {
$scope.codeName = undefined;
} else {
$scope.codeName = encodeURI(encodeURI($scope.name));
}
});
$scope.setPageRow = function(rowArr, pageSize) {
var temp = [];
if (rowArr != undefined) {
for(var i=0; i<rowArr.length; i++) {
temp.push(rowArr[i]);
}
if (rowArr.length < pageSize) {
for(var j=0; j<pageSize-rowArr.length; j++) {
temp.push({});
}
}
}
return temp;
};
// 查询分页数据:进入页面后自动查询
$scope.load = function() {
$scope.condition= {type: 'all', name: $scope.codeName};
$scope.pageData.rowCollectionPage = $scope.setPageRow([],$scope.pageSize);
$scope.pageData.noTableData = false;
$scope.pageData.loadTime = 'before';
};
$scope.load();
// 点击页面查询按钮
$scope.loadClick = function() {
$scope.condition= {type: 'all', name: $scope.codeName};
$scope.pageData.currentPage=1;
$scope.pageData.noTableData = false;
$scope.pageData.loadTime = 'before';
};
// 点击页面重置按钮
$scope.reset = function() {
$scope.name= undefined;
$scope.condition= {type: 'all', name: undefined};
$scope.pageData.noTableData = false;
$scope.pageData.loadTime = 'before';
};
{rowCollectionPage: [], totalPage: 1, currentPage:1, pages: [],count: 0, loadTime: ‘before’,noTableData: false};
在pageData中rowCollectionPage是用来存放当前页的数据,包括无数据时的空行;totalPage表示分页总页数;currentPage表示当前页;pages表示当前分页展示的所有页码数;count表示数据总数,这些好理解。
然后就是loadTime和noTableData,这2个参数是我根据需求在项目开发中自定义的,可以根据表面意思去理解。loadTime:加载时间,有before和after两个值,表示请求数据的前后,会在指令中被监控属性值的变化情况,在加载页面时首先查询一下分页数据,这时loadTime会变为after,用在load、loadClick、reset等方法中(这里loadTime是必须要配置的),定义为$scope.pageData.loadTime=’before’,指令会监控到loadTime的变化然后去请求分页查询,在然后查询后又会变为after,往复循环。noTableData:无表格数据,用于调整页面的展示,在请求分页之前是无数据的,会用空行填充当前页,默认定义为false,然后根据你请求返回的数据情况,有数据则为false,页面用数据加空行(若数据不能填满页面)填充,无数据则为true,页面首行提示无数据,下面用空行填充。
上面的解释可能有些不清楚,具体生成的效果与另一篇文章Angularjs分页指令相同,可以写代码看下效果。