DataManager.ts 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. class ListItem {
  2. data: any | null
  3. dom: HTMLElement | null
  4. tombstone: HTMLElement | null
  5. width: number
  6. height: number
  7. pos: number
  8. constructor() {
  9. this.data = null
  10. this.dom = null
  11. this.tombstone = null
  12. this.width = 0
  13. this.height = 0
  14. this.pos = 0
  15. }
  16. }
  17. export type pListItem = Partial<ListItem>
  18. export default class DataManager {
  19. public loadedNum = 0
  20. private fetching = false
  21. private hasMore = true
  22. private list: Array<pListItem>
  23. constructor(
  24. list: Array<pListItem>,
  25. private fetchFn: (len: number) => Promise<Array<any> | boolean>,
  26. private onFetchFinish: (list: Array<pListItem>, hasMore: boolean) => number
  27. ) {
  28. this.list = list || []
  29. }
  30. async update(end: number): Promise<void> {
  31. if (!this.hasMore) {
  32. end = Math.min(end, this.list.length)
  33. }
  34. // add data placeholder
  35. if (end > this.list.length) {
  36. const len = end - this.list.length
  37. this.addEmptyData(len)
  38. }
  39. // tslint:disable-next-line: no-floating-promises
  40. return this.checkToFetch(end)
  41. }
  42. add(data: Array<any>): Array<pListItem> {
  43. for (let i = 0; i < data.length; i++) {
  44. if (!this.list[this.loadedNum]) {
  45. this.list[this.loadedNum] = { data: data[i] }
  46. } else {
  47. this.list[this.loadedNum] = {
  48. ...this.list[this.loadedNum],
  49. ...{ data: data[i] },
  50. }
  51. }
  52. this.loadedNum++
  53. }
  54. return this.list
  55. }
  56. addEmptyData(len: number): Array<pListItem> {
  57. for (let i = 0; i < len; i++) {
  58. this.list.push(new ListItem())
  59. }
  60. return this.list
  61. }
  62. async fetch(len: number): Promise<Array<any> | boolean> {
  63. if (this.fetching) {
  64. return []
  65. }
  66. this.fetching = true
  67. const data = await this.fetchFn(len)
  68. this.fetching = false
  69. return data
  70. }
  71. async checkToFetch(end: number): Promise<void> {
  72. if (!this.hasMore) {
  73. return
  74. }
  75. if (end <= this.loadedNum) {
  76. return
  77. }
  78. const min = end - this.loadedNum
  79. const newData = await this.fetch(min)
  80. if (newData instanceof Array && newData.length) {
  81. this.add(newData)
  82. const currentEnd = this.onFetchFinish(this.list, true)
  83. return this.checkToFetch(currentEnd)
  84. } else if (typeof newData === 'boolean' && newData === false) {
  85. this.hasMore = false
  86. this.list.splice(this.loadedNum)
  87. this.onFetchFinish(this.list, false)
  88. }
  89. }
  90. getList() {
  91. return this.list
  92. }
  93. resetState() {
  94. this.loadedNum = 0
  95. this.fetching = false
  96. this.hasMore = true
  97. this.list = []
  98. }
  99. }