angualr配合rxcss寫一個上拉刷新下拉加載組件

直接上代碼,代碼中有詳細註釋!演示地址

  • scroll-view.compnoent.ts
import {
  Component,
  OnInit,
  ElementRef,
  Renderer2,
  ViewChild,
  OnDestroy,
  AfterViewInit,
  Input,
  HostBinding,
  EventEmitter,
  Output
} from "@angular/core";

import * as RxCSS from "rxcss";
import { Observable } from "rxjs/Observable";
import { Subject } from "rxjs/Subject";
import { fromEvent } from "rxjs/observable/fromEvent";

@Component({
  selector: "scroll-view",
  templateUrl: "./scroll-view.component.html",
  styleUrls: ["./scroll-view.component.scss"]
})
export class ScrollViewComponent implements OnInit, OnDestroy, AfterViewInit {
  @ViewChild("scroller") scroller: ElementRef;
  @ViewChild("content") content: ElementRef;

  animation$: Subject<{ x: number; y: number; z: number }> = new Subject();

  style$: any;
  // 是否上拉
  isPullUp: boolean = false;
  // 是否下拉
  isPullDown: boolean = false;

  scrollerSize: { width: number; height: number } = {
    width: 0,
    height: 0
  };
  contentSize: { width: number; height: number } = {
    width: 0,
    height: 0
  };

  @Input() upDistance: number = 80;
  @Input() downDistance: number = 80;
  @Input() timeLimit: number = 2000;

  @HostBinding("style.height.px")
  @Input()
  height: number;

  @Output() loadMore: EventEmitter<any> = new EventEmitter();
  @Output() onRefresh: EventEmitter<any> = new EventEmitter();

  // 定時器
  timer: any;

  constructor(public ele: ElementRef) {}

  ngOnInit() {
    this.height = this.ele.nativeElement.clientHeight;
    this.style$ = RxCSS(
      { mouse: this.animation$.asObservable() },
      this.scroller.nativeElement
    ).subscribe(res => {});
    // 監聽滾動事件
    fromEvent(this.scroller.nativeElement, "scroll").subscribe(res => {
      if (this.isPullDown || this.isPullUp) {
        this.reset();
      }
      let scrollTop = this.scroller.nativeElement.scrollTop;
      let scrollHeight = this.scroller.nativeElement.scrollHeight;
      let clientHeight = this.scroller.nativeElement.clientHeight;
      // 計算距離底部距離
      let toBottomDistance = scrollHeight - scrollTop - clientHeight;
      if (toBottomDistance < this.downDistance) {
        this.switchPullUp();
        // 上拉加載
        this.loadMore.emit();
      }
      if (scrollTop < this.upDistance) {
        this.switchPullDown();
        // 下拉刷新
        this.onRefresh.emit();
      }
    });
  }

  getSize() {
    this.scrollerSize = {
      width: this.scroller.nativeElement.clientWidth,
      height: this.scroller.nativeElement.clientHeight
    };
    this.contentSize = {
      width: this.content.nativeElement.clientWidth,
      height: this.content.nativeElement.clientHeight
    };
  }

  ngOnDestroy() {
    this.animation$.unsubscribe();
    this.style$.unsubscribe();
  }

  ngAfterViewInit() {
    // 獲取元素尺寸
    this.getSize();
    setTimeout(() => {
      this.switchPullDown();
    }, 0);
  }

  // 上拉加載 試圖更新
  switchPullUp() {
    if (this.isPullUp) {
      // 還原
      this.reset();
    } else {
      this.isPullUp = true;
      this.animation$.next({
        x: 0,
        y: -this.upDistance,
        z: 0
      });
      this.setTimer();
    }
  }
  // 下拉刷新 試圖更新
  switchPullDown() {
    if (this.isPullDown) {
      // 還原
      this.reset();
    } else {
      this.isPullDown = true;
      this.animation$.next({
        x: 0,
        y: this.downDistance,
        z: 0
      });
      this.setTimer();
    }
  }

  reset() {
    this.isPullUp = false;
    this.isPullDown = false;
    this.animation$.next({
      x: 0,
      y: 0,
      z: 0
    });
  }

  setTimer() {
    this.timer = setTimeout(() => {
      this.reset();
    }, this.timeLimit);
  }
}
複製代碼
  • scroll-view.component.html
<div class="scroll-refresh">
  下拉刷新
</div>
<div class="scroller" #scroller>
  <div class="scroller-content" #content>
    <ng-content></ng-content>
  </div>
</div>
<div class="scroll-loadmore">
  上拉加載
</div>
複製代碼
  • scroll-view.component.scss
:host {
    display: block;
    position: relative;
    overflow: hidden;
    z-index: 0;
    height: 100%;
}

.scroller {
    position: relative;
    overflow: auto;
    -webkit-overflow-scrolling: touch;
    max-height: 100%;
    transition: transform 0.5s cubic-bezier(0.165, 0.84, 0.44, 1);
    transform: translateX(calc(var(--mouse-x) * 1px)) translateY(calc(var(--mouse-y) * 1px)) translateY(calc(var(--mouse-z) * 1px));
    background: #efefef;
    z-index: 2;
    .scroller-content {
        height: 100%;
        position: relative;
    }
}

.scroll-loadmore,
.scroll-refresh {
    position: absolute;
    left: 0px;
    right: 0px;
    height: 80px;
    display: flex;
    flex-direction: row;
    justify-content: center;
    align-items: center;
}

.scroll-refresh {
    top: 0px;
}

.scroll-loadmore {
    bottom: 0px;
}
複製代碼
相關文章
相關標籤/搜索