我是AngualrJs菜鸟,所以特别感谢大神用AngularJs创建自己的Grid–分页组件 tm.pagination.js,帮我实现了这篇博客中最核心的部分。我主要写一下一些细节过程[[大神开源代码地址请戳我]]
大概实现效果是这样的:
前端代码是这样子的:
<html ng-app="myApp">
<head>
<meta charset="UTF-8">
<link rel="stylesheet" href="/king/resources/bootstrap-3.3.7/css/bootstrap.min.css">
<script src="/king/resources/angular-1.6.4/angular-1.6.4/angular.min.js">script>
<script src="/king/resources/pagination/tm.pagination.js">script>
<style>
.page-list .pagination {float:left;}
.page-list .pagination span {cursor: pointer;}
.page-list .pagination .separate span{cursor: default; border-top:none;border-bottom:none;}
.page-list .pagination .separate span:hover {background: none;}
.page-list .page-total {float:left; margin: 25px 20px;}
.page-list .page-total input, .page-list .page-total select{height: 26px; border: 1px solid #ddd;}
.page-list .page-total input {width: 40px; padding-left:3px;}
.page-list .page-total select {width: 50px;}
style>
head>
<body ng-controller="testController">
<div>
<div class="container">
<div class="row" >
<h1>查询列表页h1>
<div class="col-lg-3">
<p class="lead">ID:p>
<input type="text" class="form-control " ng-model="User.id">
div>
<div class="col-lg-3">
<p class="lead">Name:p>
<input type="text" class="form-control " ng-model="User.username">
div>
<div class="col-lg-3">
<p class="lead">Age:p>
<input type="text" class="form-control " ng-model="User.password">
div>
<div class="col-lg-3">
<button class="btn btn-default" ng-click="queryUser()">查询button>
div>
div>
<br><br>
<table class="table" >
<thead>
<tr>
<td class="active">IDtd>
<td class="success">USERNAMEtd>
<td class="warning">PASSWORDtd>
<td class="danger">其他的td>
<td class="success">操作td>
tr>
thead>
<tbody>
<tr ng-repeat="x in Users">
<td class="active">{{x.id}}td>
<td class="success">{{x.username}}td>
<td class="warning">{{x.password}}td>
<td class="danger">{{x.username}}td>
<td class="success" ng-click="deleteThis()"> 删除td>
tr>
tbody>
table>
<tm-pagination conf="paginationConf">tm-pagination>
div>
div>
<script>
angular.module('myApp', ['tm.pagination']).controller('testController', function($scope, $http){
// 配置分页基本参数
$scope.paginationConf = {
currentPage: 1,
itemsPerPage: 10,
perPageOptions: [10, 20, 24, 30, 40, 50,100]
};
//第一次进来取count和data
$http.post("http://localhost:8080/king/userController/both").then(function(result){
$scope.paginationConf.totalItems=result.data.count;
$scope.Users = result.data.data;
});
// 分页时候触发 获取数据条目
var reGetUsers = function(){
// 发送给后台的请求数据
//每页条数
var max= $scope.paginationConf.itemsPerPage;
//偏移量
var offset= ($scope.paginationConf.currentPage-1)*max;
$scope.User={
offset : offset,
max : max
};
$http({
method: 'POST',
params: $scope.User,
url: 'http://localhost:8080/king/userController/both'
}).then(function(result){
// 变更产品条目
$scope.Users = result.data.data;
});
};
// 通过$watch currentPage和itemperPage 当他们一变化的时候,重新获取数据条目
$scope.$watch('paginationConf.currentPage + paginationConf.itemsPerPage', reGetUsers);
//查询触发
$scope.queryUser = function(){
$http({
method: 'POST',
params: $scope.User,
url: 'http://localhost:8080/king/userController/both'
}).then(function (result) { //正确请求成功时处理
$scope.paginationConf.totalItems=result.data.count;
$scope.Users = result.data.data;
}).catch(function (result) { //捕捉错误处理
alert(result.data.Message);
});
};
})
script>
body>
html>
首先为了项目考虑,前端只能用html,这导致了第一个问题,Spring MVC配置无法访问静态的html文件。我是这么解决的:
<servlet-mapping>
<servlet-name>defaultservlet-name>
<url-pattern>*.htmlurl-pattern>
servlet-mapping>
<servlet-mapping>
<servlet-name>defaultservlet-name>
<url-pattern>*.jpgurl-pattern>
servlet-mapping>
<servlet-mapping>
<servlet-name>defaultservlet-name>
<url-pattern>*.jsurl-pattern>
servlet-mapping>
<servlet-mapping>
<servlet-name>defaultservlet-name>
<url-pattern>*.cssurl-pattern>
servlet-mapping>
注意:上面这段代码必须写在DispatcherServlet前面,表示不用你管我。
现在可以访问到我们的页面了,第二个问题出现了:
@RequestMapping(value="/display")
public ModelAndView toExitPage(HttpServletRequest request,
HttpServletResponse response)throws Exception{
Map model = new HashMap();
return new ModelAndView("AngularJs/newpagination",model);
}
通过RequestMapping注解配置找到这里,ModelAndView只返回了视图,并没有携带数据。因为html是静态的,无法通过el表达式接收${数据}。所以我只好加载完页面后,立即ajax异步请求一次。就是这一段代码的作用:
$http.post("http://localhost:8080/king/userController/both").then(function(result){
$scope.paginationConf.totalItems=result.data.count;
$scope.Users = result.data.data;
});
那么后台Controller里是怎么写的呢?
@RequestMapping(value="/both", method={RequestMethod.POST,RequestMethod.GET})
@ResponseBody
public Map<String, Object> queryBoth(User user, HttpServletRequest request) {
List<User> list = new ArrayList<User>();
list = userService.getByUser(user);
Map<String, Object> model=new HashMap<String, Object>();
model.put("data", list);
user.setMax(null);
Integer totalItems=userService.getByUser(user).size();
model.put("count", totalItems);
return model;
}
这段代码主要做了两件事,一是取要展示的数据,存进list,二是计算数据总量(给分页框架用)。可能会有人说,totalItems取list.size()不就可以了。是不可以的,因为list是分页查询的,它的size最多为每页的条数,这就是为什么要user.setMax(null)。剩下的就是AngualrJs在前端取数据应用和展示了,前面代码里写的很清楚,就不说了。
基本的流程操作完成了,说一下大神框架的应用细节。
1 需要显示的配置分页基本参数,可以把这一段封装在tm.pagination.js文件里。
// 配置分页基本参数
$scope.paginationConf = {
currentPage: 1,
itemsPerPage: 10,
perPageOptions: [10, 20, 24, 30, 40, 50,100]
};
link: function(scope, element, attrs) {
// 封装进来 配置分页基本参数
scope.conf = {
currentPage: 1,
itemsPerPage: 10,
perPageOptions: [10, 20, 24, 30, 40, 50,100]
};
var conf = scope.conf;
2 不太懂的地方,为什么点击分页的时候,会监测到paginationConf.currentPage、paginationConf.itemsPerPage这两个参数发生变化,tm.pagination.js里的代码是怎么和这两个参数对应起来的。
下午回来自答一波:因为用了双向绑定。
<tm-pagination conf="paginationConf">tm-pagination>
angular.module('tm.pagination', []).directive('tmPagination',[function(){
return {
/*
1.restrict
(字符串)可选参数,指明指令在DOM里面以什么形式被声明;取值有:
E(元素),A(属性),C(类),M(注释),其中默认值为A;
当然也可以两个一起用,比如EA.表示即可以是元素也可以是属性。
*/
restrict: 'EA',
/*
* template(字符串或者函数)可选参数,可以是:
(1)一段HTML文本
(2)一个函数,可接受两个参数tElement和tAttrs
*/
template: '<div class="page-list">' +
'<ul class="pagination" ng-show="conf.totalItems > 0">' +
'<li ng-class="{disabled: conf.currentPage == 1}" ng-click="prevPage()"><span>«span>li>' +
'<li ng-repeat="item in pageList track by $index" ng-class="{active: item == conf.currentPage, separate: item == \'...\'}" ' +
'ng-click="changeCurrentPage(item)">' +
'<span>{{ item }}span>' +
'li>' +
'<li ng-class="{disabled: conf.currentPage == conf.numberOfPages}" ng-click="nextPage()"><span>»span>li>' +
'ul>' +
'<div class="page-total" ng-show="conf.totalItems > 0">' +
'每页<select ng-model="conf.itemsPerPage" ng-options="option for option in conf.perPageOptions " ng-change="changeItemsPerPage()">select>' +
'/共<strong>{{ conf.totalItems }}strong>条 ' +
'跳转至<input type="text" ng-model="jumpPageNum" ng-keyup="jumpPageKeyUp($event)"/>页' +
'div>' +
'<div class="no-items" ng-show="conf.totalItems <= 0">暂无数据div>' +
'div>',
replace: true,
/*
* 布尔值或者对象,可选参数,默认值为false,表示继承父级作用域。
* 如果值为true,表示继承父作用域,并创建自己的作用域(子作用域)
* 如果为对象,{},则表示创建一个全新的隔离作用域。
* 当我们将scope的值设置为{}时,没办法从父级作用域中继承到color的值了。
*/
scope: {
//使用'='进行双向绑定 (使用@来进行单向文本(字符串)绑定)
conf: '='
},
// 通过$watch currentPage和itemperPage 当他们一变化的时候,重新获取数据条目
$scope.$watch('paginationConf.currentPage + paginationConf.itemsPerPage', reGetUsers);
3 reGetUsers函数,要自己显示的计算max和offset。太low了,是自己的代码能力问题,肯定能封装一下的。
4 点击查询的时候,函数代码和reGetUsers函数是一样的,但是我还没学会在AngularJs中怎么复用函数。
总结:虽然算是成功了,但是有许多细节上的问题可以优化,希望各路大神指出不足之处和可以改进的地方。