foundation.ts 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. import { isObject, get } from 'lodash';
  2. import BaseFoundation, { DefaultAdapter } from '../base/foundation';
  3. import { numbers } from './constants';
  4. import { throttle } from 'lodash';
  5. export interface CarouselAdapter<P = Record<string, any>, S = Record<string, any>> extends DefaultAdapter<P, S> {
  6. notifyChange: (activeIndex: number, preIndex: number) => void;
  7. setNewActiveIndex: (activeIndex: number) => void;
  8. setPreActiveIndex: (activeIndex: number) => void;
  9. setIsReverse: (isReverse: boolean) => void;
  10. setIsInit: (isInit: boolean) => void;
  11. }
  12. class CarouselFoundation<P = Record<string, any>, S = Record<string, any>> extends BaseFoundation<CarouselAdapter<P, S>, P, S> {
  13. throttleChange: any;
  14. constructor(adapter: CarouselAdapter<P, S>) {
  15. super({ ...adapter });
  16. this.throttleChange = throttle(this.onIndicatorChange, this.getSwitchingTime());
  17. }
  18. _interval = null;
  19. play(interval: number): void {
  20. if (this._interval) {
  21. clearInterval(this._interval);
  22. }
  23. this._interval = setInterval(() => {
  24. this.next();
  25. }, interval);
  26. }
  27. stop(): void {
  28. if (this._interval){
  29. clearInterval(this._interval);
  30. }
  31. }
  32. goTo(activeIndex: number): void {
  33. const { activeIndex: stateActiveIndex } = this.getStates();
  34. const targetIndex = this.getValidIndex(activeIndex);
  35. this._adapter.setIsReverse(stateActiveIndex > targetIndex);
  36. if (this.getIsControledComponent()) {
  37. this._notifyChange(targetIndex);
  38. } else {
  39. this._notifyChange(targetIndex);
  40. this.handleNewActiveIndex(targetIndex);
  41. }
  42. }
  43. next(): void {
  44. const { activeIndex: stateActiveIndex } = this.getStates();
  45. const targetIndex = this.getValidIndex(stateActiveIndex + 1);
  46. this._adapter.setIsReverse(false);
  47. if (this.getIsControledComponent()) {
  48. this._notifyChange(targetIndex);
  49. } else {
  50. this._notifyChange(targetIndex);
  51. this.handleNewActiveIndex(targetIndex);
  52. }
  53. }
  54. prev(): void {
  55. const { activeIndex: stateActiveIndex } = this.getStates();
  56. const targetIndex = this.getValidIndex(stateActiveIndex - 1);
  57. this._adapter.setIsReverse(true);
  58. if (this.getIsControledComponent()) {
  59. this._notifyChange(targetIndex);
  60. } else {
  61. this._notifyChange(targetIndex);
  62. this.handleNewActiveIndex(targetIndex);
  63. }
  64. }
  65. destroy(): void {
  66. this._unregisterInterval();
  67. }
  68. _unregisterInterval() {
  69. if (this._interval) {
  70. clearInterval(this._interval);
  71. this._interval = null;
  72. }
  73. }
  74. _notifyChange(activeIndex: number): void {
  75. const { activeIndex: stateActiveIndex, isInit } = this.getStates();
  76. if (isInit){
  77. this._adapter.setIsInit(false);
  78. }
  79. if (stateActiveIndex !== activeIndex) {
  80. this._adapter.setPreActiveIndex(stateActiveIndex);
  81. this._adapter.notifyChange(activeIndex, stateActiveIndex);
  82. }
  83. }
  84. getValidIndex(index: number): number {
  85. const { children } = this.getStates();
  86. return (index + children.length) % children.length;
  87. }
  88. getSwitchingTime(): number {
  89. const { autoPlay, speed } = this.getProps();
  90. const autoPlayType = typeof autoPlay;
  91. if (autoPlayType === 'boolean' && autoPlay){
  92. return numbers.DEFAULT_INTERVAL + speed;
  93. }
  94. if (isObject(autoPlay)){
  95. return get(autoPlay, 'interval', numbers.DEFAULT_INTERVAL) + speed;
  96. }
  97. return speed;
  98. }
  99. getIsControledComponent(): boolean {
  100. return this._isInProps('activeIndex');
  101. }
  102. handleAutoPlay(): void {
  103. const { autoPlay } = this.getProps();
  104. const autoPlayType = typeof autoPlay;
  105. if ((autoPlayType === 'boolean' && autoPlay) || isObject(autoPlay)){
  106. this.play(this.getSwitchingTime());
  107. }
  108. }
  109. handleKeyDown(event: any): void{
  110. if (event.key === 'ArrowLeft') {
  111. this.prev();
  112. }
  113. if (event.key === 'ArrowRight') {
  114. this.next();
  115. }
  116. }
  117. onIndicatorChange(activeIndex: number): void {
  118. const { activeIndex: stateActiveIndex } = this.getStates();
  119. this._adapter.setIsReverse(stateActiveIndex > activeIndex);
  120. this._notifyChange(activeIndex);
  121. if (!this.getIsControledComponent()) {
  122. this.handleNewActiveIndex(activeIndex);
  123. }
  124. }
  125. handleNewActiveIndex(activeIndex: number): void {
  126. const { activeIndex: stateActiveIndex } = this.getStates();
  127. if (stateActiveIndex !== activeIndex) {
  128. this._adapter.setNewActiveIndex(activeIndex);
  129. }
  130. }
  131. getDefaultActiveIndex(): number {
  132. let activeIndex;
  133. const props = this.getProps();
  134. if ('activeIndex' in props) {
  135. activeIndex = props.activeIndex;
  136. } else if ('defaultActiveIndex' in props) {
  137. activeIndex = props.defaultActiveIndex;
  138. }
  139. return activeIndex;
  140. }
  141. }
  142. export default CarouselFoundation;