my-lib/list-view/list-view.ts
CdkScrollable
changeDetection | ChangeDetectionStrategy.OnPush |
encapsulation | ViewEncapsulation.None |
selector | list-view |
styleUrls | list-view.less, |
templateUrl | ./list-view.html |
Properties |
|
Methods |
Inputs |
Outputs |
Accessors |
constructor(ele: ElementRef, _scroll: ScrollDispatcher, ngZone: NgZone, render: Renderer2, ruler: ViewportRuler, cd: ChangeDetectorRef)
|
||||||||||||||||||||||||||||
Defined in my-lib/list-view/list-view.ts:66
|
||||||||||||||||||||||||||||
Parameters :
|
dataSource
|
Type: |
Defined in my-lib/list-view/list-view.ts:59
|
height
|
Type:
Default value: |
Defined in my-lib/list-view/list-view.ts:34
|
horizontal
|
Type: |
Defined in my-lib/list-view/list-view.ts:40
|
initialListSize
|
Type: |
Defined in my-lib/list-view/list-view.ts:57
|
loading
|
Type:
Default value: |
Defined in my-lib/list-view/list-view.ts:65
|
onEndReachedThreshold
|
Type:
Default value: |
Defined in my-lib/list-view/list-view.ts:49
|
page
|
Type:
Default value: |
Defined in my-lib/list-view/list-view.ts:54
|
pageSize
|
Type:
Default value: |
Defined in my-lib/list-view/list-view.ts:55
|
pullToRefresh
|
Type:
Default value: |
Defined in my-lib/list-view/list-view.ts:36
|
scrollEventThrottle
|
Type:
Default value: |
Defined in my-lib/list-view/list-view.ts:47
|
scrollRenderAheadDistance
|
Type:
Default value: |
Defined in my-lib/list-view/list-view.ts:51
|
onEndReached
|
$event type: EventEmitter<any>
|
Defined in my-lib/list-view/list-view.ts:26
|
onScroll
|
$event type: EventEmitter<any>
|
Defined in my-lib/list-view/list-view.ts:25
|
onTopReached
|
$event type: EventEmitter<any>
|
Defined in my-lib/list-view/list-view.ts:27
|
markForCheck |
markForCheck()
|
Defined in my-lib/list-view/list-view.ts:191
|
Returns :
void
|
ngAfterContentInit |
ngAfterContentInit()
|
Defined in my-lib/list-view/list-view.ts:80
|
Returns :
void
|
ngOnInit |
ngOnInit()
|
Defined in my-lib/list-view/list-view.ts:86
|
Returns :
void
|
refreshSize |
refreshSize()
|
Defined in my-lib/list-view/list-view.ts:199
|
Returns :
void
|
_horizontal |
_horizontal:
|
Type : boolean
|
Default value : false
|
Defined in my-lib/list-view/list-view.ts:38
|
_viewportSize |
_viewportSize:
|
Type : any
|
Defined in my-lib/list-view/list-view.ts:61
|
Public cd |
cd:
|
Type : ChangeDetectorRef
|
Defined in my-lib/list-view/list-view.ts:74
|
content |
content:
|
Type : ElementRef
|
Decorators : ViewChild
|
Defined in my-lib/list-view/list-view.ts:66
|
contentRect |
contentRect:
|
Type : any
|
Defined in my-lib/list-view/list-view.ts:197
|
contentScroller |
contentScroller:
|
Type : Scroller
|
Defined in my-lib/list-view/list-view.ts:62
|
Public ele |
ele:
|
Type : ElementRef
|
Defined in my-lib/list-view/list-view.ts:69
|
Public render |
render:
|
Type : Renderer2
|
Defined in my-lib/list-view/list-view.ts:72
|
ruler |
ruler:
|
Type : ViewportRuler
|
Defined in my-lib/list-view/list-view.ts:30
|
scroller |
scroller:
|
Type : Scroller
|
Defined in my-lib/list-view/list-view.ts:63
|
scrollerRect |
scrollerRect:
|
Type : any
|
Defined in my-lib/list-view/list-view.ts:198
|
horizontal |
gethorizontal()
|
Defined in my-lib/list-view/list-view.ts:43
|
sethorizontal(val: any)
|
Defined in my-lib/list-view/list-view.ts:40
|
import {
ViewEncapsulation, Component,
Input, ElementRef, Renderer2,
ChangeDetectionStrategy,
ContentChild, TemplateRef,
NgZone, OnInit, HostBinding,
ContentChildren, QueryList,
EventEmitter, Output, ViewChild,
AfterContentInit, ChangeDetectorRef
} from '@angular/core';
import { Antd } from '../antd';
import { ScrollDispatcher, CdkScrollable, ViewportRuler } from '@angular/cdk/scrolling';
import { Platform } from '@angular/cdk/platform';
import { Scroller, isMeepoTrue } from 'meepo-utils';
const listView = 'am-list-view';
@Component({
selector: 'list-view',
templateUrl: './list-view.html',
encapsulation: ViewEncapsulation.None,
changeDetection: ChangeDetectionStrategy.OnPush,
styleUrls: ['./list-view.less', './patch.less']
})
export class ListViewComponent extends CdkScrollable implements OnInit, AfterContentInit {
@Output() onScroll: EventEmitter<any> = new EventEmitter();
@Output() onEndReached: EventEmitter<any> = new EventEmitter();
@Output() onTopReached: EventEmitter<any> = new EventEmitter();
// 试图
ruler: ViewportRuler;
// 高度控制
@HostBinding('style.height.px')
@Input()
height: number = 0;
// 下拉刷新
@Input() pullToRefresh: boolean = false;
// 是否水平
_horizontal: boolean = false;
@Input()
set horizontal(val: any) {
this._horizontal = isMeepoTrue(val);
}
get horizontal() {
return this._horizontal;
}
// 滑动监听延时
@Input() scrollEventThrottle: number = 50;
// 延时执行
@Input() onEndReachedThreshold: number = 1000;
// 距离底部多少触发
@Input() scrollRenderAheadDistance: number = 70;
// 页码及数量
@Input() page: number = 1;
@Input() pageSize: number = 10;
// 初始数量
@Input() initialListSize: boolean;
// 数据加载器
@Input() dataSource: any;
_viewportSize: any;
contentScroller: Scroller;
scroller: Scroller;
@Input() loading: boolean = false;
@ViewChild('content') content: ElementRef;
constructor(
public ele: ElementRef,
_scroll: ScrollDispatcher,
private ngZone: NgZone,
public render: Renderer2,
ruler: ViewportRuler,
public cd: ChangeDetectorRef
) {
super(ele, _scroll, ngZone);
this.ruler = ruler;
}
ngAfterContentInit() {
if (this.horizontal && !this.height) {
this.height = this.content.nativeElement.firstChild.clientHeight + 5;
}
}
ngOnInit() {
// 内容区
this.contentScroller = new Scroller(this.content);
// 容器区
this.scroller = new Scroller(this.ele);
this.render.addClass(this.ele.nativeElement, `${listView}-scrollview`);
// 监听滑动
this.elementScrolled()
.debounceTime(this.scrollEventThrottle)
// 处理数据
.map(res => {
const content = this.contentScroller.getViewportRect();
const scroller = this.scroller.getViewportRect();
return {
top: content.top,
right: content.width - content.left - scroller.width,
bottom: content.height - content.top - scroller.height,
left: content.left,
}
})
.do(res => {
this.onScroll.emit(res);
})
// 过滤不符合的条件
.filter(res => {
let data: boolean = false;
const maxHeight = this.scrollRenderAheadDistance;
if (this.horizontal) {
// 如果水平
if (this.pullToRefresh) {
// 有刷新 返回左右值
data = res.left < maxHeight || res.right < maxHeight;
} else {
// 没有刷新
data = res.right < maxHeight;
}
} else {
// 垂直
if (this.pullToRefresh) {
// 有刷新 返回上下值
data = res.top < maxHeight || res.bottom < maxHeight;
} else {
// 没有刷新
data = res.bottom < maxHeight;
}
}
return data;
})
.map(res => {
const data = {
top: res.top < this.scrollRenderAheadDistance,
right: res.right < this.scrollRenderAheadDistance,
bottom: res.bottom < this.scrollRenderAheadDistance,
left: res.left < this.scrollRenderAheadDistance,
}
if (this.pullToRefresh) {
if (this.horizontal) {
return {
refresh: data.left,
more: data.right
}
} else {
return {
refresh: data.top,
more: data.bottom
}
}
} else {
if (this.horizontal) {
return {
refresh: false,
more: data.right
}
} else {
return {
refresh: false,
more: data.bottom
}
}
}
})
// 延时
.subscribe(res => {
if (!this.loading) {
if (res.refresh) {
this.onTopReached.emit(this);
}
if (res.more) {
this.onEndReached.emit(this);
}
this.loading = true;
this.markForCheck();
setTimeout(() => {
this.loading = false;
this.markForCheck();
}, this.onEndReachedThreshold);
}
});
// 试图变化
this.ruler.change().subscribe(res => {
this.refreshSize();
});
super.ngOnInit();
}
markForCheck() {
this.ngZone.run(() => {
this.cd.markForCheck();
});
}
contentRect: any;
scrollerRect: any;
refreshSize() {
this.contentRect = this.contentScroller.getViewportRect();
this.scrollerRect = this.scroller.getViewportRect();
}
}
<div #content class="am-list-view-scrollview-content">
<ng-content></ng-content>
<div style="position: relative;top: 0px;">
<div class="am-list-footer" #loadingTip>
<div style="padding: 10px; text-align: center;color: gray;">
<span *ngIf="loading">加载中...</span>
<span *ngIf="!loading">加载完成</span>
</div>
</div>
</div>
</div>