ng实现分页组件

本文大纲
  1. 1. 1. data方式
    1. 1.1. 样式:paging.component.css
    2. 1.2. 模板:paging.component.html
    3. 1.3. TS:paging.component.ts
    4. 1.4. 使用:
  2. 2. 2. dom方式
    1. 2.1. 样式:paging.component.css
    2. 2.2. 模板:paging.component.html
    3. 2.3. TS:paging.component.ts
    4. 2.4. 使用:

在此记录一个简单的分页组件实现。

1. data方式


样式:paging.component.css

代码折叠 代码展开
1
2
3
4
5
6
7
8
9
10
11
12
13
14
.pagination{vertical-align:middle;}
.pagination a,.pagination span{padding:0 5px;margin-right:5px;border: 1px solid #ddd;text-align:center;line-height:26px;display:inline-block;min-width:20px;color:#000; vertical-align:middle;}
.pagination .pageem{line-height:28px;display:inline-block;vertical-align:middle;font-style:normal;color:#aaa;}
.pagination .pageem1{margin-left:2em;margin-right:4px;}
.pagination .pageem2{margin-left:5px;}
.pagination a {text-decoration: none;}
.pagination a:hover,.pagination a:active {border-color:#666;color: #000;}
.pagination .pagefirst,.pagination .pageprev,.pagination .pagelast,.pagination .pagenext{font-size:12px;}
.pagination .pageprev{margin-right:2em;}
.pagination .pagenext{margin-left:2em;}
.pagination .current {border-color:transparent;color:blue;}
.pagination .disabled {border: 1px solid #EEE;color: #DDD;}
.pagination .pagepoints{border-color:transparent;}
.pagination .pageselect{box-sizing:border-box;height:26px;vertical-align:middle;}

模板:paging.component.html

代码折叠 代码展开
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
<div>
<span *ngIf="showInfo" style="float:right;line-height:28px;">
记录: <span class="red">{{total}}</span> 页: <span id="cur" class="red">{{curP}}</span>/<span class="red">{{pageCount}}</span>
</span>
<div *ngIf="list.length>1" class="pagination">
<ng-container *ngFor="let item of list">
<!-- item: { value: 1, type: 'first', link: true, disable: false, text: conf.wordFt } -->
<!-- value: 值,
type: first/prev/next/last/normal/current/elp,
link: 是否链接, disable:是否禁用, text:铵钮文字
-->
<ng-container *ngIf="item.type==='normal'">
<a *ngIf="item.link" href="javascript:;" (click)="evChangePage(item.value)">{{item.text}}</a>
</ng-container>
<ng-container *ngIf="item.type!=='normal'">
<a *ngIf="item.link" href="javascript:;"
[ngClass]="{
current:item.type==='current', disabled:item.disable,
pagenext: item.type==='next', pageprev: item.type==='prev',
pagefirst: item.type==='first', pagelast: item.type==='last',
pagepoints: item.type==='elp'
}"
(click)="evChangePage(item.value)">{{item.text}}</a>
<span *ngIf="!item.link"
[ngClass]="{
current:item.type==='current', disabled:item.disable,
pagenext: item.type==='next', pageprev: item.type==='prev',
pagefirst: item.type==='first', pagelast: item.type==='last',
pagepoints: item.type==='elp'
}">{{item.text}}</span>
</ng-container>
</ng-container>
<ng-container *ngIf="ifSelect && pageCount>1">
<em class="pageem pageem1">跳到第</em><select [ngModel]="curP"
(change)="evChangePage(selects.value)" #selects>
<option *ngFor="let item of pagesArr; index as vv" [value]="vv+1">{{vv+1}}</option>
</select><em class="pageem pageem2">页</em>
</ng-container>
</div>

</div>

TS:paging.component.ts

代码折叠 代码展开
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
import { Component, OnInit, Input, Output, EventEmitter, OnChanges } from '@angular/core';
import { ObjTpye } from '../../util/types';

const build = (curP: number, pageCount: number, conf: ObjTpye) => {
const list = [];
// list-item: { value: 1, type: 'first', link: true, disable: false, text: conf.wordFt }
/*
value: 值,
type: first/prev/next/last/normal/current/elp,
link: 是否链接, disable:是否禁用, text:铵钮文字
*/
if (pageCount < 1) { pageCount = 1; }
if (curP > pageCount) { curP = pageCount; }
if (pageCount > 1) {
// first and previous button
if (curP > 1) {
if (conf.showFtLt) {
list.push({ value: 1, type: 'first', link: true, disable: false, text: conf.wordFt });
}
if (conf.showPvNt) {
list.push({ value: curP - 1, type: 'prev', link: true, disable: false, text: conf.wordPv });
}
} else {
if (conf.showFtLt) {
list.push({ value: '', type: 'first', link: false, disable: true, text: conf.wordFt });
}
if (conf.showPvNt) {
list.push({ value: '', type: 'prev', link: false, disable: true, text: conf.wordPv });
}
}
// pages
if (pageCount < 7 + (conf.adjacents * 2)) {
for (let item = 1; item <= pageCount; item++) {
if (item === curP) {
list.push({ value: '', type: 'current', link: false, disable: false, text: item });
} else {
list.push({ value: item, type: 'normal', link: true, disable: false, text: item });
}
}
// enough pages to hide some
} else if (pageCount >= 7 + (conf.adjacents * 2)) {
// close to beginning only hide later pages
if (curP < 1 + (conf.adjacents * 3)) {
for (let item = 1; item <= (4 + (conf.adjacents * 2)) - 1; item++) {
if (item === curP) {
list.push({ value: '', type: 'current', link: false, disable: false, text: item });
} else {
list.push({ value: item, type: 'normal', link: true, disable: false, text: item });
}
}
list.push({ value: '', type: 'elp', link: false, disable: false, text: conf.wordElp });
list.push({ value: pageCount - 1, type: 'normal', link: true, disable: false, text: pageCount - 1 });
list.push({ value: pageCount, type: 'normal', link: true, disable: false, text: pageCount });
// in middle hide some front and some back
} else if (pageCount - (conf.adjacents * 2) > curP && curP > (conf.adjacents * 2)) {
list.push({ value: 1, type: 'normal', link: true, disable: false, text: 1 });
list.push({ value: 2, type: 'normal', link: true, disable: false, text: 2 });
list.push({ value: '', type: 'elp', link: false, disable: false, text: conf.wordElp });
for (let item = curP - conf.adjacents; item <= curP + conf.adjacents; item++) {
if (item === curP) {
list.push({ value: '', type: 'current', link: false, disable: false, text: item });
} else {
list.push({ value: item, type: 'normal', link: true, disable: false, text: item });
}
}
list.push({ value: '', type: 'elp', link: false, disable: false, text: conf.wordElp });
list.push({ value: pageCount - 1, type: 'normal', link: true, disable: false, text: pageCount - 1 });
list.push({ value: pageCount, type: 'normal', link: true, disable: false, text: pageCount });
// close to end only hide early pages
} else {
list.push({ value: 1, type: 'normal', link: true, disable: false, text: 1 });
list.push({ value: 2, type: 'normal', link: true, disable: false, text: 2 });
list.push({ value: '', type: 'elp', link: false, disable: false, text: conf.wordElp });
for (let item = (pageCount - (1 + (conf.adjacents * 3))); item <= pageCount; item++) {
if (item === curP) {
list.push({ value: '', type: 'current', link: false, disable: false, text: item });
} else {
list.push({ value: item, type: 'normal', link: true, disable: false, text: item });
}
}
}
}
// last and next button
if (curP < pageCount) {
if (conf.showPvNt) {
list.push({ value: curP + 1, type: 'next', link: true, disable: false, text: conf.wordNt });
}
if (conf.showFtLt) {
list.push({ value: pageCount, type: 'last', link: true, disable: false, text: conf.wordLt });
}
} else {
if (conf.showPvNt) {
list.push({ value: '', type: 'next', link: false, disable: true, text: conf.wordNt });
}
if (conf.showFtLt) {
list.push({ value: '', type: 'last', link: false, disable: true, text: conf.wordLt });
}
}
} else if (pageCount === 1 && conf.lte2pShow) {
if (conf.showFtLt) {
list.push({ value: '', type: 'first', link: false, disable: true, text: conf.wordFt });
}
if (conf.showPvNt) {
list.push({ value: '', type: 'prev', link: false, disable: true, text: conf.wordPv });
}
list.push({ value: '', type: 'current', link: false, disable: false, text: 1 });
if (conf.showPvNt) {
list.push({ value: '', type: 'next', link: false, disable: true, text: conf.wordNt });
}
if (conf.showFtLt) {
list.push({ value: '', type: 'last', link: false, disable: true, text: conf.wordLt });
}
}
return list;
};

const conf = {
adjacents: 2, lte2pShow: false, ifSelect: true, showPvNt: true, showFtLt: true,
wordElp: '...', wordPv: '< 上一页', wordNt: '下一页 >', wordFt: '|<< 首 页', wordLt: '末 页 >>|'
};

@Component({
selector: 'app-paging',
templateUrl: './paging.component.html',
styleUrls: ['./paging.component.css']
})
export class PagingDataComponent implements OnInit, OnChanges {
pagesArr = [];
ifSelect = true;
list = [];
pageCount = 0;
// tslint:disable-next-line:no-input-rename
@Input('pShowInfo') showInfo = false;
// tslint:disable-next-line:no-input-rename
@Input('pCurP') curP = 1;
// tslint:disable-next-line:no-input-rename
@Input('pSize') pSize = 10;
// tslint:disable-next-line:no-input-rename
@Input('pTotal') total = 0;
// tslint:disable-next-line:no-output-on-prefix
@Output() onPagingChange: EventEmitter<number> = new EventEmitter();

ngOnInit() { }
ngOnChanges() {
this.calc();
}
evChangePage(n: number | string) {
n = Number(n);
this.onPagingChange.emit(n);
this.curP = n;
this.calc();
}
private calc() {
this.pageCount = Math.ceil(this.total / this.pSize);
this.pagesArr = new Array(this.pageCount || 1).fill(1);
this.list = build(this.curP, this.pageCount, conf);
}

}

使用:

代码折叠 代码展开
1
2
3
4
5
6
<app-paging
(onPagingChange)="onPagingChange($event)"
[pCurP]="currentPage"
[pSize]="pageSize"
[pTotal]="totalRecord"
></app-paging>
代码折叠 代码展开
1
2
3
4
5
6
7
8
currentPage: number = 1;
pageSize: number = 10;
totalRecord: number = 231;

onPagingChange(page: number) {
this.currentPage = page;
// ...
}

2. dom方式

样式:paging.component.css

代码折叠 代码展开
1
2
3
4
5
6
7
8
9
10
11
12
13
14
.pagination{vertical-align:middle;}
.pagination a,.pagination span{padding:0 5px;margin-right:5px;border: 1px solid #ddd;text-align:center;line-height:26px;display:inline-block;min-width:20px;color:#000; vertical-align:middle;}
.pagination .pageem{line-height:28px;display:inline-block;vertical-align:middle;font-style:normal;color:#aaa;}
.pagination .pageem1{margin-left:2em;margin-right:4px;}
.pagination .pageem2{margin-left:5px;}
.pagination a {text-decoration: none;}
.pagination a:hover,.pagination a:active {border-color:#666;color: #000;}
.pagination .pagefirst,.pagination .pageprev,.pagination .pagelast,.pagination .pagenext{font-size:12px;}
.pagination .pageprev{margin-right:2em;}
.pagination .pagenext{margin-left:2em;}
.pagination .current {border-color:transparent;color:blue;}
.pagination .disabled {border: 1px solid #EEE;color: #DDD;}
.pagination .pagepoints{border-color:transparent;}
.pagination .pageselect{box-sizing:border-box;height:26px;vertical-align:middle;}

模板:paging.component.html

代码折叠 代码展开
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
<div>

<span *ngIf="showInfo" style="float:right;line-height:28px;">
记录: <span class="red">{{total}}</span> 页: <span id="cur" class="red">{{curP}}</span>/<span class="red">{{pageCount}}</span>
</span>

<div *ngIf="pageCount>1" class="pagination">
<!-- first and previous button -->
<ng-container *ngIf="curP>1">
<a *ngIf="conf.showFtLt" class="pagefirst" (click)="evChangePage(1)" href="javascript:;">{{conf.wordFt}}</a>
<a *ngIf="conf.showPvNt" class="pageprev" (click)="evChangePage(curP - 1)"
href="javascript:;">{{conf.wordPv}}</a>
</ng-container>
<ng-container *ngIf="curP<=1">
<span *ngIf="conf.showFtLt" class="pagefirst disabled">{{conf.wordFt}}</span>
<span *ngIf="conf.showPvNt" class="pageprev disabled">{{conf.wordPv}}</span>
</ng-container>
<!-- pages -->
<ng-container *ngIf="pageCount < 7 + (conf.adjacents * 2)">
<ng-container *ngFor="let item of makeEndArr(pageCount)">
<span *ngIf="item === curP" class="current">{{item}}</span>
<a *ngIf="item !== curP" (click)="evChangePage(item)" href="javascript:;">{{item}}</a>
</ng-container>
</ng-container>
<!-- enough pages to hide some -->
<ng-container *ngIf="pageCount >= 7 + (conf.adjacents * 2)">
<!-- close to beginning only hide later pages -->
<ng-container *ngIf="flag1">
<ng-container *ngFor="let item of makeEndArr(4 + (conf.adjacents * 2)-1)">
<span *ngIf="item === curP" class="current">{{item}}</span>
<a *ngIf="item !== curP" (click)="evChangePage(item)" href="javascript:;">{{item}}</a>
</ng-container>
<span class="pagepoints">{{conf.wordElp}}</span>
<a (click)="evChangePage(pageCount - 1)" href="javascript:;">{{pageCount - 1}}</a>
<a (click)="evChangePage(pageCount)" href="javascript:;">{{pageCount}}</a>
</ng-container>
<!-- in middle hide some front and some back -->
<ng-container *ngIf="flag2">
<a (click)="evChangePage(1)" href="javascript:;">1</a>
<a (click)="evChangePage(2)" href="javascript:;">2</a>
<span class="pagepoints">{{conf.wordElp}}</span>
<ng-container *ngFor="let item of makeEndArr(curP + conf.adjacents,curP - conf.adjacents)">
<span *ngIf="item === curP" class="current">{{item}}</span>
<a *ngIf="item !== curP" (click)="evChangePage(item)" href="javascript:;">{{item}}</a>
</ng-container>
<span class="pagepoints">{{conf.wordElp}}</span>
<a (click)="evChangePage(pageCount-1)" href="javascript:;">{{pageCount-1}}</a>
<a (click)="evChangePage(pageCount)" href="javascript:;">{{pageCount}}</a>
</ng-container>
<!-- close to end only hide early pages -->
<ng-container *ngIf="flag3">
<a (click)="evChangePage(1)" href="javascript:;">1</a>
<a (click)="evChangePage(2)" href="javascript:;">2</a>
<span class="pagepoints">{{conf.wordElp}}</span>
<ng-container *ngFor="let item of makeEndArr(pageCount, pageCount - (1 + (conf.adjacents * 3)))">
<span *ngIf="item === curP" class="current">{{item}}</span>
<a *ngIf="item !== curP" (click)="evChangePage(item)" href="javascript:;">{{item}}</a>
</ng-container>
</ng-container>
</ng-container>
<!-- last and next button -->
<ng-container *ngIf="curP < pageCount">
<a *ngIf="conf.showFtLt" class="pagenext"
(click)="evChangePage(curP + 1)" href="javascript:;">{{conf.wordNt}}</a>
<a *ngIf="conf.showPvNt" class="pagelast"
(click)="evChangePage(pageCount)" href="javascript:;">{{conf.wordLt}}</a>
</ng-container>
<ng-container *ngIf="curP >= pageCount">
<span *ngIf="conf.showPvNt" class="pagenext disabled">{{conf.wordNt}}</span>
<span *ngIf="conf.showFtLt" class="pagelast disabled">{{conf.wordLt}}</span>
</ng-container>
<ng-container *ngIf="conf.ifSelect">
<em class="pageem pageem1">跳到第</em><select [ngModel]="curP"
(change)="evChangePage(selects.value)" #selects>
<option *ngFor="let item of makeEndArr(pageCount)" [value]="item">{{item}}</option>
</select><em class="pageem pageem2">页</em>
</ng-container>
</div>

<div *ngIf="pageCount<=1&&conf.lte2pShow" class="pagination">
<span *ngIf="conf.showFtLt" class="pagefirst disabled">{{conf.wordFt}}</span>
<span *ngIf="conf.showPvNt" class="pageprev disabled">{{conf.wordPv}}</span>
<span class="current">1</span>
<span *ngIf="conf.showPvNt" class="pagenext disabled">{{conf.wordNt}}</span>
<span *ngIf="conf.showFtLt" class="pagelast disabled">{{conf.wordLt}}</span>
</div>

</div>

TS:paging.component.ts

代码折叠 代码展开
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
import { Component, OnInit, Input, Output, EventEmitter, OnChanges } from '@angular/core';

@Component({
selector: 'app-paging',
templateUrl: './paging.component.html',
styleUrls: ['./paging.component.css']
})
export class PagingDomComponent implements OnInit, OnChanges {

conf = {
adjacents: 2, lte2pShow: false, ifSelect: true, showPvNt: true, showFtLt: true,
wordElp: '...', wordPv: '< 上一页', wordNt: '下一页 >', wordFt: '|<< 首 页', wordLt: '末 页 >>|'
};
pageCount = 0;
flag1 = false;
flag2 = false;
flag3 = false;
// tslint:disable-next-line:no-input-rename
@Input('pShowInfo') showInfo = false;
// tslint:disable-next-line:no-input-rename
@Input('pCurP') curP = 1;
// tslint:disable-next-line:no-input-rename
@Input('pSize') pSize = 10;
// tslint:disable-next-line:no-input-rename
@Input('pTotal') total = 0;
// tslint:disable-next-line:no-output-on-prefix
@Output() onPagingChange: EventEmitter<number> = new EventEmitter();

ngOnInit() { }
ngOnChanges() {
this.calc();
}
evChangePage(n: number|string) {
n = Number(n);
this.onPagingChange.emit(n);
this.curP = n;
this.calc();
}
private calc() {
this.flag1 = this.flag2 = this.flag3 = false;
this.pageCount = Math.ceil(this.total / this.pSize);
if (this.pageCount < 1) { this.pageCount = 1; }
if (this.curP > this.pageCount) { this.curP = this.pageCount; }
if (this.curP < 1 + (this.conf.adjacents * 3)) {
this.flag1 = true;
} else if (this.pageCount - (this.conf.adjacents * 2) > this.curP && this.curP > (this.conf.adjacents * 2)) {
this.flag2 = true;
} else {
this.flag3 = true;
}
}
makeEndArr(stop: number, start: number = 1) {
const arr = [];
do {
arr[arr.length] = start++;
} while (start <= stop);
return arr;
}
}

使用:

代码折叠 代码展开
1
2
3
4
5
6
<app-paging
(onPagingChange)="onPagingChange($event)"
[pCurP]="currentPage"
[pSize]="pageSize"
[pTotal]="totalRecord"
></app-paging>
代码折叠 代码展开
1
2
3
4
5
6
7
8
currentPage: number = 1;
pageSize: number = 10;
totalRecord: number = 231;

onPagingChange(page: number) {
this.currentPage = page;
// ...
}