Rxjs - ngPagination

由于群里很多人问 NG2 分页怎么做.我在这里做个 demo

基本组件结构

主路由组件 注入 service providers: [ROUTER_PROVIDERS, PagerService, HTTP_PROVIDERS]

组件主体分为

  • list
  • footer
<app-test-list></app-test-list>
<app-test-footer></app-test-footer>

list 组件

主要是 Rxjs 实现,所以采用 onPush

@Component({
moduleId: module.id,
selector: 'app-test-list',
templateUrl: 'test-list.component.html',
styleUrls: ['test-list.component.css'],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class TestListComponent implements OnInit {
numbers: Observable<number[]>;
userNumber: Observable<number>;
footer: Observable<number>;
constructor(public page: PagerService) {
this.numbers = this.page.displayItems$;
}
ngOnInit() {
}

}

这里直接 Observable 放到 template 上

  • numbers 就是显示数据的数组
@Component({
moduleId: module.id,
selector: 'app-test-footer',
templateUrl: 'test-footer.component.html',
styleUrls: ['test-footer.component.css'],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class TestFooterComponent implements OnInit {

numbers: Observable<number[]>;
currentPage: Observable<number>;
constructor(public page: PagerService) {
this.numbers = this.page.footerArray$;
this.currentPage = this.page.currentPage$;
}
ngOnInit() {
}
changePage(e) {
this.page.currentPage$.next(e);
}
}
  • numbers 就是计算出的 footer 数组
  • currentPage 额外现实个当前的页号,方便验证

services 主体解析

import { Injectable } from '@angular/core';
import {Observable, BehaviorSubject} from 'rxjs/Rx';
import { Http } from '@angular/http';

@Injectable()
export class PagerService {

numEachPage: number = 3;
currentPage$: BehaviorSubject<number>;

data$: Observable<any>;
footerItem$: Observable<number>;
displayItems$: Observable<number[]>;

userNumber$: Observable<number>;
footerArray$: Observable<number[]>;

constructor(public http: Http) {
this.currentPage$ = new BehaviorSubject(1);

this.displayItems$ = this.currentPage$.distinctUntilChanged().flatMap(cp => {
return this.data$
.map(data => data.slice((cp - 1) * this.numEachPage, cp * this.numEachPage));
});
this.data$ = this.http
.get('http://jsonplaceholder.typicode.com/users')
.map(res => res.json());

this.userNumber$ = this.data$
.map(x => x.length)
.do(x => console.log(x));

this.footerItem$ = this.userNumber$
.map(x => Math.ceil(x / this.numEachPage));

this.footerArray$ = this.footerItem$
.flatMap(x => {
return Observable.from([Array.from(Array(x).keys()).map(y => y + 1)]);
});

}

}

几个流说下:

  • currentPage$ 这个是点击 footer 的时候留出当前是第几页
<div class="pager">
<a (click)="changePage(number)" *ngFor="let number of numbers | async; let index=index">
{{index+1}}
</a>
</div>
changePage(e) {
this.page.currentPage$.next(e);
}

看下这里通过 click 把当前的页数传出去

  • data$ 请求到总数据数组 – 这个实际项目中应该单独一个 module 去做
  • userNumber$ 是根据总数据数据得到数据的数量,为了后面计算 footer 的数组
  • footerItem$ 这个就是计算 footer 里最多是多少页
  • footerArray$ 通过 footerItem$ 来产生一个数组的流
  • displayItems$ 根据当前选中的页号和总数据来筛选出当前页需要显示的数据

这里 hardcode 了一个每页显示的数量 numEachPage: number = 3;

源码地址: https://github.com/dreambo8563/rx-paginationDemo/tree/master

改进

经过群友指点,创建 array 的方法改为如下,cool

this.footerArray$ = this.footerItem$.flatMap(x => {
return Observable.range(1, x).reduce((acc, v) => acc.concat(v), [])
})