この記事で共有した内容は、Angular 6 のスクロール リスト コンポーネントのカプセル化の分析に関するものです。必要な友人はそれを参照できます。
学習はinput
とoutput
を組み合わせるプロセスであるべきです これがこの記事を書いた理由です。 input
和output
相结合之过程,这就是写这篇文章的原因。
在大屏幕展示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
看起来是一直往上走的。
<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>
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; 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
スクロールリストは大画面表示の Web アプリでよく使用されます。何度か試した結果、かなり良いアイデアに落ち着きました。
リスト ヘッダーのヘッド部分は固定されていますが、ボディ部分は上にスクロールします。
本文部分をスクロールした後、データを更新する必要があります。最終的には、データベース内のすべての関連データが上向きスクロール形式で表示されます。
p
を table
の外層にコンテナとして配置し、table
によって top を定期的に > 値に設定し、<code>table
が途中で実行されるのを待ち、バックエンドからデータを要求し、コンポーネント tbody
を動的に作成して、それを table code> を実行し、前の <code>tbody
がなくなったら (見えなくなったら)、このコンポーネントを削除します。このアイデアは実現可能に思えましたが、実際には問題が発生しました。 前のコンポーネントを削除すると、table
の高さが減り、テーブルはすぐに下に落ちます。 これは明らかに私たちが望んでいることではなく、副作用は非常に深刻です。 最後に、仕事帰りにテーブルを2つも使わない方法を思いつきました。 1 つの table
のみを使用して定期的に移動し、行程の半分が完了したら、タイマーをクリアし、位置をリセットし、データの半分を更新します。つまり、配列内のデータの前半が削除され、バックグラウンドから取得された新しいデータが配列に接続されます。 このようにして、データを継続的に更新することができ、table
は増加し続けているように見えます。 コード🎜url
を渡すだけで済み、データの更新を含むすべての操作がコンポーネント自体によって完了します。これによりコンポーネントのカプセル化が完了し、再利用が容易になります。 🎜🎜まとめと感想🎜🎜 1. 更新データはソースで更新する、つまりDOM要素の追加や削除は行わないでください。この操作は面倒でパフォーマンスも低くなります。ソースに置くということは、コンポーネントクラスの表示データを格納する配列について大騒ぎすることを意味します。 🎜2. バックグラウンドで要求された新しいデータは、早めに準備して別の一時配列に配置する必要があります。キャッシュや一時レジスタに相当します。 🎜3. コンポーネントを関数として想像します。このパラメーターが存在する限り、コンポーネントは他の値に依存せずに正常に動作します。疎結合。 🎜4. 関数型プログラミングの考え方を強化する React
の特徴ですが、angular
も使えると常々感じています。 🎜🎜関連する推奨事項: 🎜🎜🎜 AngularJs のカスタム命令の設定方法とカスタム命令の命名規則🎜🎜🎜🎜🎜 AngularJs のモデル、コントローラー (Controller)、ビュー (View) の関係は何ですか? (写真と文章)🎜🎜🎜🎜以上がAngular 6 のスクロール リスト コンポーネントのカプセル化の分析の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。