【Angular 6】转动列表组件的封装

媒介

进修应为inputoutput相结合之历程,这就是写这篇文章的缘由。
在大屏幕展现web APP中,常常会用到转动列表。经由频频尝试,肯定了一个还不错的思绪。

需求

  • 列表表头thead部份静止,而tbody部份向上转动。
  • tbody部份转动完毕以后,须要革新数据,终究结果是以向上转动的情势将数据库中悉数相干数据展现出来。

剖析

假如数据量比较小的话,我们完整能够将数据一次性悉数拿出来,放到DOM中举行轮回转动。现实就是相似轮播图的结果。

但如有许多数据的话,如许做极可能形成内存泄漏。天然,我们能够想到将列表数据分页。我最初的主意是,在table的外层放一个div作为容器,然后table定时向上增添top值,等table跑了一半时,向后端要求数据,动态建立一个组件tbody插进去到table中,然后等前面一个tbody走完时(看不见了),将这个组件删除。该主意看起来可行的,然则实践中遇到了不少贫苦。在删除前面的组件时,会致使table的高度减小,表格霎时掉下去了。这明显不是我们想要的,副作用挺大的。

既然如许,我把tbody分开到两个table里,两个table轮回。当前一个table下面没有数据时,第二个table最先走,等第一个table完整走出div,将它位置重置到div的下面,并更新数据,然后反复之间的行动。完成起来轻微有点贫苦,不过结果还说得过去,差强人意。问题是,两个定时器不稳定,翻开其他软件,再回来时,两个table跑的不一致了。这个天赋性疾病,setInterval就是不够准确的,两个定时器一同轻易涌现合营不好的状况。

终究,在放工回家的路上,我想到了一个不须要两个table的要领。只用一个table定时上移,走完一半时,消灭定时器,重置位置,并更新一半的数据。也就是去除数组中前一半数据,将背景拉过来的新数据拼接在数组上。如许就可以够完成数据的延续革新,而且table看起来是一向往上走的。

代码

scroll-table.component.html

<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>

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;
        div{
            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也能够的。

    原文作者:wuchunxu
    原文地址: https://segmentfault.com/a/1190000015721692
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞