首頁  >  文章  >  web前端  >  對Angular 6中滾動列表組件的封裝的分析

對Angular 6中滾動列表組件的封裝的分析

不言
不言原創
2018-07-23 11:35:581840瀏覽

這篇文章給大家分享的內容是關於Angular 6中滾動清單元件的封裝的分析,有一定的參考價值,有需要的朋友可以參考一下。

前言

學習應為inputoutput結合過程,這就是寫這篇文章的原因。
在大螢幕展示web APP中,常會用到捲動清單。經過幾次嘗試,確定了一個還不錯的想法。

需求

  • 列表表頭thead部分靜止,而tbody部分向上捲動。

  • tbody部分滾動結束之後,需要刷新數據,最終效果是以向上滾動的形式將資料庫中全部相關數據展示出來。

分析

如果資料量比較小的話,我們完全可以將資料一次全部拿出來,放到DOM中進行循環滾動。實際上就是類似輪播圖的效果。

但若有很多資料的話,這樣做很可能造成記憶體外洩。自然,我們可以想到將列表資料分頁。我最初的想法是,在table的外層放一個p作為容器,然後table定時向上增加top值,等table跑了一半時,向後端請求數據,動態創建一個元件tbody插入到table中,然後等前面一個tbody走完時(看不見了),將這個元件刪除。該想法看起來可行的,但是實踐上遇到了不少麻煩。 在刪除前面的元件時,會導致table的高度減少,表格瞬間掉下去了。 這顯然不是我們想要的,副作用還蠻大的。

既然這樣,我把tbody分開到兩個table裡,兩個table循環。 當前一個table下面沒有資料時,第二個table開始走,等第一個table完全走出p ,將它位置重置到p的下面,並更新數據,然後重複之間的動作。 完成起來稍微有點麻煩,不過效果還說得過去,差強人意。 問題是,兩個定時器不穩定,打開其他軟體,再回來時,兩個table跑的不一致了。 這個先天性疾病,setInterval就是不夠精確的,兩個計時器一起容易出現配合不好的情況。

最終,在下班回家的路上,我想到了一個不需要兩個table的方法。 只用一個table定時上移,走完一半時,清除定時器,重置位置,並更新一半的資料。也就是移除數組中前一半數據,將後台拉過來的新數據拼接在數組上。 這樣就可以實現資料的持續刷新,而table看起來是一直往上走的。

程式碼

scroll-table.component.html

<p class="table-container">
  <table class="head-show">
    <thead>
      <tr>
        <th style="width:12.8%;">字段1</th>
        <th style="width:12.8%;">字段2</th>
        <th>字段3</th>
        <th style="width:12.8%;">字段4</th>
      </tr>
    </thead>
  </table>
  <p class="scroller-container">
    <table #scroller class="scroller">
      <tbody>
        <tr *ngFor="let ele of tbody">
          <td style="width:12.8%;">{{ele.field01}}</td>
          <td style="width:12.8%;">{{ele.field02}}</td>
          <td><p>{{ele.field03}}</p></td>
          <td style="width:12.8%;">{{ele.field04}}</td>
        </tr>
      </tbody>
    </table>
  </p>
</p>

scroll-table.component.ts

import { Component, OnInit, ViewChild, ElementRef, Input } from '@angular/core';
import { HttpService } from '../http.service';

@Component({
  selector: 'app-scroll-table',
  templateUrl: './scroll-table.component.html',
  styleUrls: ['./scroll-table.component.scss']
})
export class ScrollTableComponent implements OnInit {
  tbody: any = [];
  @Input() url; //将地址变成组件的一个参数,也就是输入属性
  //控制滚动的元素
  @ViewChild('scroller') scrollerRef: ElementRef;
  timer: any;

  freshData: any;

  pageNow = 1;//pageNow是当前数据的页码,初始化为1

  constructor(private http: HttpService) {}

  ngOnInit() {
    //初始化拿到native
    let scroller: HTMLElement = this.scrollerRef.nativeElement;
    this.http.sendRequest(this.url).subscribe((data :any[]) => {
      
      this.tbody = data.concat(data);
    });
    //开启定时器
    this.timer = this.go(scroller);
  }

  getFreshData() {
  //每次请求数据时,pageNow自增1
    this.http.sendRequest(`${this.url}?pageNow=${++this.pageNow}`).subscribe((data:any[]) => {
      if(data.length<10) {
        //数据丢弃,pageNow重置为1
        this.pageNow = 1;
      }
      this.freshData = data;
    });
  }
  
  go(scroller) {
    var
      moved = 0,
      step = -50,
      timer = null,
      task = () => {
        let style = document.defaultView.getComputedStyle(scroller, null);
        let top = parseInt(style.top, 10);
        if (moved < 10) {
          if(moved===0) {
            this.getFreshData();
          }
          scroller.style.transition = "top 0.5s ease";
          moved++;
          scroller.style.top = top + step + 'px';

        } else {
          //重置top,moved,清除定时器
          clearInterval(timer);
          moved = 0;
          scroller.style.transition = "none";
          scroller.style.top = '0px';
          //更新数据
          this.tbody = this.tbody.slice(10).concat(this.freshData);
          timer = setInterval(task,1000);
        }
      };
    timer = setInterval(task, 1000);
  }
}

scroll-table.component.scss

.table-container {
    width: 100%;
    height: 100%;
}
.head-show {
    border-top: 1px solid #4076b9;
    height: 11.7%;
}
.scroller-container {
    border-bottom: 1px solid #4076b9;
    //border: 1px solid #fff;
    width: 100%;
    //height: 88.3%;
    height: 250px;
    box-sizing: border-box;
    overflow: hidden;
    position:relative;
    .scroller {
        position: absolute;
        top:0;
        left:0;
        transition: top .5s ease;
    }
}
table {
    width: 100%;
    border-collapse: collapse;
    table-layout: fixed;
    //border-bottom:1px solid #4076b9;
    th {
        
        border-bottom:1px dashed #2d4f85;
        color:#10adda;
        padding:8px 2px;
        font-size: 14px;
    }
    td {
        border-bottom: 1px dashed #2d4f85;
        font-size: 12px;
        
        color:#10adda;
        position: relative;
        height: 49px;
        p{
            padding:0 2px;
            box-sizing: border-box;
            text-align:center;
            display: table-cell;
            overflow: hidden;
            vertical-align: middle;
        }
        //border-width:1px 0 ;
    }
}

這樣實現的效果是,該元件只需要傳入一個參數url,然後所有的操作、包含更新數據,全部由元件自行完成。從而完成了組件的封裝,以便於復用。

總結與思考

1、更新資料應該放在源頭更新,也就是說,不要去新增和刪除DOM元素,這樣操作麻煩,效能也低。放在源頭的意思是,在元件類別中儲存展示資料的那個陣列上做文章。
2、後台請求新資料應該提早準備就緒,放在另一個臨時數組中。它相當於一個緩存,一個暫存器。
3、我將元件想像成一個函數,它只有一個參數,就是資料的位址,只要有這個參數,元件就能正常運作,不依賴其他任何值。鬆散耦合性。
4、加強函數式程式設計思想,雖然這是React的特色,但我總覺得angular也可以的。

相關推薦:

AngularJs自訂指令可以如何來設定以及自訂指令的命名規範

AngularJs中model、Controller(控制器)和View(視圖)之間有什麼樣的關係? (圖文)

#

以上是對Angular 6中滾動列表組件的封裝的分析的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn