index.tsx 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. import React from 'react'
  2. import Pivot, { IPivotProps } from './Pivot'
  3. type ScrollConfigType = 'vertical' | 'horizontal' | 'duplex'
  4. type ScrollRole = 'header' | 'body'
  5. export class ScrollablePivot extends React.Component<IPivotProps, {}> {
  6. private scrollThrottle: boolean = false
  7. private scrollEnd: number
  8. private headerScrolling = false
  9. private bodyScrolling = false
  10. private columnHeaderListenerCallback: (e) => void = null
  11. private columnFooterListenerCallback: (e) => void = null
  12. private rowHeaderListenerCallback: (e) => void = null
  13. private tableBodyListenerCallback: (e) => void = null
  14. private pivot: Pivot = null
  15. public shouldComponentUpdate (nextProps: IPivotProps) {
  16. return nextProps.renderType !== 'loading'
  17. }
  18. public componentDidMount () {
  19. const { rowHeader, columnHeader, columnFooter, tableBody } = this.pivot
  20. this.columnHeaderListenerCallback = this.duplexScroll({
  21. type: 'horizontal',
  22. role: 'header',
  23. follower: [tableBody, columnFooter]
  24. })
  25. this.columnFooterListenerCallback = this.duplexScroll({
  26. type: 'horizontal',
  27. role: 'header',
  28. follower: [tableBody, columnHeader]
  29. })
  30. this.rowHeaderListenerCallback = this.duplexScroll({
  31. type: 'vertical',
  32. role: 'header',
  33. follower: [tableBody]
  34. })
  35. this.tableBodyListenerCallback = this.duplexScroll({
  36. type: 'duplex',
  37. role: 'body',
  38. follower: [columnHeader, columnFooter, rowHeader]
  39. })
  40. columnHeader.addEventListener('scroll', this.columnHeaderListenerCallback, false)
  41. columnFooter.addEventListener('scroll', this.columnFooterListenerCallback, false)
  42. rowHeader.addEventListener('scroll', this.rowHeaderListenerCallback, false)
  43. tableBody.addEventListener('scroll', this.tableBodyListenerCallback, false)
  44. }
  45. public componentWillUnmount () {
  46. const { rowHeader, columnHeader, columnFooter, tableBody } = this.pivot
  47. columnHeader.removeEventListener('scroll', this.columnHeaderListenerCallback, false)
  48. columnFooter.removeEventListener('scroll', this.columnFooterListenerCallback, false)
  49. rowHeader.removeEventListener('scroll', this.rowHeaderListenerCallback, false)
  50. tableBody.removeEventListener('scroll', this.tableBodyListenerCallback, false)
  51. }
  52. private duplexScroll = (config: { type: ScrollConfigType, role: ScrollRole, follower: HTMLElement[]}) => (e) => {
  53. if (!this.scrollThrottle) {
  54. this.scrollThrottle = true
  55. if (!this.headerScrolling && !this.bodyScrolling) {
  56. if (config.role === 'header') {
  57. this.headerScrolling = true
  58. } else {
  59. this.bodyScrolling = true
  60. }
  61. } else {
  62. if (config.role === 'header' && !this.headerScrolling ||
  63. config.role === 'body' && !this.bodyScrolling) {
  64. this.scrollThrottle = false
  65. return
  66. }
  67. }
  68. requestAnimationFrame(() => {
  69. clearTimeout(this.scrollEnd)
  70. this.syncScroll(config.type, config.follower, e)
  71. this.scrollThrottle = false
  72. this.scrollEnd = window.setTimeout(() => {
  73. this.headerScrolling = false
  74. this.bodyScrolling = false
  75. }, 100)
  76. })
  77. }
  78. }
  79. private syncScroll (type: ScrollConfigType, follower: HTMLElement[], e) {
  80. switch (type) {
  81. case 'horizontal':
  82. follower[0].scrollLeft = follower[1].scrollLeft = e.target.scrollLeft
  83. break
  84. case 'vertical':
  85. follower[0].scrollTop = e.target.scrollTop
  86. break
  87. default:
  88. follower[0].scrollLeft = follower[1].scrollLeft = e.target.scrollLeft
  89. follower[2].scrollTop = e.target.scrollTop
  90. break
  91. }
  92. }
  93. public render () {
  94. return (
  95. <Pivot {...this.props} ref={(f) => this.pivot = f} />
  96. )
  97. }
  98. }
  99. export default ScrollablePivot