>  기사  >  웹 프론트엔드  >  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스크롤링 목록은 대형 화면 디스플레이 웹 앱에서 자주 사용됩니다. 여러 번 시도한 끝에 꽤 좋은 아이디어를 얻었습니다.

요구 사항

  • 목록 헤더의 thead 부분은 고정된 반면 tbody 부분은 위쪽으로 스크롤됩니다.

  • 본문 부분을 스크롤한 후 데이터를 새로 고쳐야 합니다. 최종 효과는 데이터베이스의 모든 관련 데이터를 위쪽 스크롤 형식으로 표시하는 것입니다.

분석

데이터의 양이 상대적으로 적다면 모든 데이터를 한 번에 꺼내어 순환 스크롤을 위해 DOM에 넣을 수 있습니다. 사실 이는 회전목마의 효과와 유사합니다.
하지만 데이터가 많으면 메모리 누수가 발생할 수 있습니다. 당연히 목록 데이터의 페이지 매김을 생각할 수 있습니다. 내 초기 아이디어는 ptable의 외부 레이어에 컨테이너로 넣은 다음 tabletop를 주기적으로 > 값으로 설정하고, <code>table이 중간에 실행될 때까지 기다리고, 백엔드에서 데이터를 요청하고, tbody 구성 요소를 동적으로 생성하여 table에 삽입합니다. code>를 선택한 다음 이전 tbody가 사라지면(눈에 보이지 않게) 이 구성 요소를 삭제하세요. 아이디어는 실현 가능해 보였지만 실제로는 문제에 봉착했습니다. 이전 구성요소를 삭제하면 테이블의 높이가 줄어들어 테이블이 즉시 무너집니다. 이것은 분명히 우리가 원하는 것이 아니며 부작용도 상당히 심각합니다.

이 경우 tbody를 두 개의 table과 두 개의 table 루프로 분리했습니다. 이전 테이블 아래에 데이터가 없으면 두 번째 테이블이 걷기 시작하고 첫 번째 테이블이 완전히 걷기를 기다립니다. p 중 해당 위치를 p 아래로 재설정하고 데이터를 업데이트한 다음 그 사이의 작업을 반복합니다. 완성하기가 조금 번거롭기는 하지만 효과는 무난하고 만족스럽습니다. 문제는 두 타이머가 불안정하다는 것입니다. 다른 소프트웨어를 열고 돌아오면 두 테이블이 일관되지 않게 실행됩니다. 이 선천성 질환의 경우 setInterval은 정확하지 않으며 두 타이머의 조정이 제대로 이루어지지 않는 경향이 있습니다.

드디어 퇴근길에 테이블 두 개가 필요 없는 방법이 생각났어요. 하나의 테이블만 사용하여 정기적으로 이동하세요. 여행의 절반이 완료되면 타이머를 지우고 위치를 재설정하고 데이터의 절반을 업데이트하세요. 즉, 배열에 있는 데이터의 전반부가 제거되고, 배경에서 가져온 새로운 데이터가 배열에 접합됩니다. 이런 방식으로 데이터를 지속적으로 새로 고칠 수 있으며 테이블이 계속해서 늘어나는 것처럼 보입니다.
Code🎜

scroll-table.comComponent.html

rrreee

scroll-table.comComponent.ts

rrreee

scroll-table.comComponent.scss

rrreee🎜 그 결과 구성요소는 하나의 매개변수 url만 전달하면 되며, 데이터 업데이트를 포함한 모든 작업은 구성요소 자체에서 완료됩니다. 이렇게 하면 구성 요소 캡슐화가 완료되고 재사용이 용이해집니다. 🎜🎜요약 및 생각🎜🎜1. 업데이트 데이터는 소스에서 업데이트해야 합니다. 즉, DOM 요소를 추가하거나 삭제하지 마십시오. 이 작업은 번거롭고 성능이 낮습니다. 소스에 넣는다는 것은 구성 요소 클래스에 표시 데이터를 저장하는 배열에 대해 소란을 피우는 것을 의미합니다. 🎜2. 백그라운드에서 요청된 새 데이터는 일찍 준비하여 다른 임시 배열에 배치해야 합니다. 캐시와 임시 레지스터에 해당합니다. 🎜3. 구성 요소를 함수로 상상합니다. 이 매개 변수가 하나만 있으면 구성 요소는 다른 값에 의존하지 않고 정상적으로 작동합니다. 느슨한 커플 링. 🎜4. 함수형 프로그래밍의 개념을 강화하세요. 이것이 React의 특징이지만, Angular도 사용할 수 있다는 느낌을 항상 받습니다. 🎜🎜관련 권장 사항: 🎜🎜🎜AngularJs 사용자 지정 지침 및 사용자 지정 지침의 명명 규칙을 설정하는 방법🎜🎜🎜🎜🎜AngularJs에서 모델, 컨트롤러(Controller) 및 뷰(View) 간의 관계는 무엇입니까? (사진 및 텍스트)🎜🎜🎜🎜

위 내용은 Angular 6의 스크롤 목록 구성요소 캡슐화 분석의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.