學習應爲input
和output
相結合之過程,這就是寫這篇文章的緣由。
在大屏幕展現web APP中,常常會用到滾動列表。通過幾回嘗試,肯定了一個還不錯的思路。css
若是數據量比較小的話,咱們徹底能夠將數據一次性所有拿出來,放到DOM中進行循環滾動。實際就是相似輪播圖的效果。html
但如有不少數據的話,這樣作極可能形成內存泄露。天然,咱們能夠想到將列表數據分頁。我最初的想法是,在table
的外層放一個div
做爲容器,而後table
定時向上增長top
值,等table
跑了一半時,向後端請求數據,動態建立一個組件tbody
插入到table
中,而後等前面一個tbody
走完時(看不見了),將這個組件刪除。該想法看起來可行的,可是實踐中遇到了很多麻煩。在刪除前面的組件時,會致使table
的高度減少,表格瞬間掉下去了。這顯然不是咱們想要的,反作用挺大的。web
既然這樣,我把tbody
分開到兩個table
裏,兩個table
循環。當前一個table
下面沒有數據時,第二個table
開始走,等第一個table
徹底走出div
,將它位置重置到div
的下面,並更新數據,而後重複之間的動做。完成起來稍微有點麻煩,不過效果還說得過去,差強人意。問題是,兩個定時器不穩定,打開其餘軟件,再回來時,兩個table跑的不一致了。這個先天性疾病,setInterval
就是不夠精確的,兩個定時器一塊兒容易出現配合很差的狀況。數據庫
最終,在下班回家的路上,我想到了一個不須要兩個table的方法。只用一個table
定時上移,走完一半時,清除定時器,重置位置,並更新一半的數據。也就是去除數組中前一半數據,將後臺拉過來的新數據拼接在數組上。這樣就能夠實現數據的持續刷新,而且table
看起來是一直往上走的。編程
<div 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> <div 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><div>{{ele.field03}}</div></td> <td style="width:12.8%;">{{ele.field04}}</td> </tr> </tbody> </table> </div> </div>
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); } }
.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; div{ padding:0 2px; box-sizing: border-box; text-align:center; display: table-cell; overflow: hidden; vertical-align: middle; } //border-width:1px 0 ; } }
這樣實現的效果是,該組件只須要傳入一個參數url
,而後全部的操做、包括更新數據,所有由組件自身完成。從而完成了組件的封裝,便於複用。後端
一、更新數據應該放在源頭更新,也就是說,不要去添加和刪除DOM元素,這樣操做麻煩,性能也低。放在源頭的意思是,在組件類中存儲展現數據的那個數組上作文章。
二、後臺請求新數據應該提前準備就緒,放在另外一個臨時數組中。它至關於一個緩存,一個暫存器。
三、我將組件想象成一個函數,它只有一個參數,就是數據的地址,只要有這個參數,組件就能正常工做,不依賴於其餘任何值。鬆耦合性。
四、增強函數式編程思想,雖然這是React
的特點,但我總以爲angular
也能夠的。數組