swiper.js 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  1. function _extends() { _extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
  2. import React, { useRef, useState, useEffect, forwardRef } from 'react';
  3. import SwiperCore from 'swiper';
  4. import { getParams } from '../components-shared/get-params.js';
  5. import { mountSwiper } from '../components-shared/mount-swiper.js';
  6. import { needsScrollbar, needsNavigation, needsPagination, uniqueClasses, extend } from '../components-shared/utils.js';
  7. import { renderLoop, calcLoopedSlides } from './loop.js';
  8. import { getChangedParams } from '../components-shared/get-changed-params.js';
  9. import { getChildren } from './get-children.js';
  10. import { updateSwiper } from '../components-shared/update-swiper.js';
  11. import { renderVirtual } from './virtual.js';
  12. import { updateOnVirtualData } from '../components-shared/update-on-virtual-data.js';
  13. import { useIsomorphicLayoutEffect } from './use-isomorphic-layout-effect.js';
  14. import { SwiperContext } from './context.js';
  15. const Swiper = /*#__PURE__*/forwardRef(function (_temp, externalElRef) {
  16. let {
  17. className,
  18. tag: Tag = 'div',
  19. wrapperTag: WrapperTag = 'div',
  20. children,
  21. onSwiper,
  22. ...rest
  23. } = _temp === void 0 ? {} : _temp;
  24. let eventsAssigned = false;
  25. const [containerClasses, setContainerClasses] = useState('swiper');
  26. const [virtualData, setVirtualData] = useState(null);
  27. const [breakpointChanged, setBreakpointChanged] = useState(false);
  28. const initializedRef = useRef(false);
  29. const swiperElRef = useRef(null);
  30. const swiperRef = useRef(null);
  31. const oldPassedParamsRef = useRef(null);
  32. const oldSlides = useRef(null);
  33. const nextElRef = useRef(null);
  34. const prevElRef = useRef(null);
  35. const paginationElRef = useRef(null);
  36. const scrollbarElRef = useRef(null);
  37. const {
  38. params: swiperParams,
  39. passedParams,
  40. rest: restProps,
  41. events
  42. } = getParams(rest);
  43. const {
  44. slides,
  45. slots
  46. } = getChildren(children);
  47. const onBeforeBreakpoint = () => {
  48. setBreakpointChanged(!breakpointChanged);
  49. };
  50. Object.assign(swiperParams.on, {
  51. _containerClasses(swiper, classes) {
  52. setContainerClasses(classes);
  53. }
  54. });
  55. const initSwiper = () => {
  56. // init swiper
  57. Object.assign(swiperParams.on, events);
  58. eventsAssigned = true;
  59. swiperRef.current = new SwiperCore(swiperParams);
  60. swiperRef.current.loopCreate = () => {};
  61. swiperRef.current.loopDestroy = () => {};
  62. if (swiperParams.loop) {
  63. swiperRef.current.loopedSlides = calcLoopedSlides(slides, swiperParams);
  64. }
  65. if (swiperRef.current.virtual && swiperRef.current.params.virtual.enabled) {
  66. swiperRef.current.virtual.slides = slides;
  67. const extendWith = {
  68. cache: false,
  69. slides,
  70. renderExternal: setVirtualData,
  71. renderExternalUpdate: false
  72. };
  73. extend(swiperRef.current.params.virtual, extendWith);
  74. extend(swiperRef.current.originalParams.virtual, extendWith);
  75. }
  76. };
  77. if (!swiperElRef.current) {
  78. initSwiper();
  79. } // Listen for breakpoints change
  80. if (swiperRef.current) {
  81. swiperRef.current.on('_beforeBreakpoint', onBeforeBreakpoint);
  82. }
  83. const attachEvents = () => {
  84. if (eventsAssigned || !events || !swiperRef.current) return;
  85. Object.keys(events).forEach(eventName => {
  86. swiperRef.current.on(eventName, events[eventName]);
  87. });
  88. };
  89. const detachEvents = () => {
  90. if (!events || !swiperRef.current) return;
  91. Object.keys(events).forEach(eventName => {
  92. swiperRef.current.off(eventName, events[eventName]);
  93. });
  94. };
  95. useEffect(() => {
  96. return () => {
  97. if (swiperRef.current) swiperRef.current.off('_beforeBreakpoint', onBeforeBreakpoint);
  98. };
  99. }); // set initialized flag
  100. useEffect(() => {
  101. if (!initializedRef.current && swiperRef.current) {
  102. swiperRef.current.emitSlidesClasses();
  103. initializedRef.current = true;
  104. }
  105. }); // mount swiper
  106. useIsomorphicLayoutEffect(() => {
  107. if (externalElRef) {
  108. externalElRef.current = swiperElRef.current;
  109. }
  110. if (!swiperElRef.current) return;
  111. if (swiperRef.current.destroyed) {
  112. initSwiper();
  113. }
  114. mountSwiper({
  115. el: swiperElRef.current,
  116. nextEl: nextElRef.current,
  117. prevEl: prevElRef.current,
  118. paginationEl: paginationElRef.current,
  119. scrollbarEl: scrollbarElRef.current,
  120. swiper: swiperRef.current
  121. }, swiperParams);
  122. if (onSwiper) onSwiper(swiperRef.current); // eslint-disable-next-line
  123. return () => {
  124. if (swiperRef.current && !swiperRef.current.destroyed) {
  125. swiperRef.current.destroy(true, false);
  126. }
  127. };
  128. }, []); // watch for params change
  129. useIsomorphicLayoutEffect(() => {
  130. attachEvents();
  131. const changedParams = getChangedParams(passedParams, oldPassedParamsRef.current, slides, oldSlides.current, c => c.key);
  132. oldPassedParamsRef.current = passedParams;
  133. oldSlides.current = slides;
  134. if (changedParams.length && swiperRef.current && !swiperRef.current.destroyed) {
  135. updateSwiper({
  136. swiper: swiperRef.current,
  137. slides,
  138. passedParams,
  139. changedParams,
  140. nextEl: nextElRef.current,
  141. prevEl: prevElRef.current,
  142. scrollbarEl: scrollbarElRef.current,
  143. paginationEl: paginationElRef.current
  144. });
  145. }
  146. return () => {
  147. detachEvents();
  148. };
  149. }); // update on virtual update
  150. useIsomorphicLayoutEffect(() => {
  151. updateOnVirtualData(swiperRef.current);
  152. }, [virtualData]); // bypass swiper instance to slides
  153. function renderSlides() {
  154. if (swiperParams.virtual) {
  155. return renderVirtual(swiperRef.current, slides, virtualData);
  156. }
  157. if (!swiperParams.loop || swiperRef.current && swiperRef.current.destroyed) {
  158. return slides.map(child => {
  159. return /*#__PURE__*/React.cloneElement(child, {
  160. swiper: swiperRef.current
  161. });
  162. });
  163. }
  164. return renderLoop(swiperRef.current, slides, swiperParams);
  165. }
  166. return /*#__PURE__*/React.createElement(Tag, _extends({
  167. ref: swiperElRef,
  168. className: uniqueClasses(`${containerClasses}${className ? ` ${className}` : ''}`)
  169. }, restProps), /*#__PURE__*/React.createElement(SwiperContext.Provider, {
  170. value: swiperRef.current
  171. }, slots['container-start'], /*#__PURE__*/React.createElement(WrapperTag, {
  172. className: "swiper-wrapper"
  173. }, slots['wrapper-start'], renderSlides(), slots['wrapper-end']), needsNavigation(swiperParams) && /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("div", {
  174. ref: prevElRef,
  175. className: "swiper-button-prev"
  176. }), /*#__PURE__*/React.createElement("div", {
  177. ref: nextElRef,
  178. className: "swiper-button-next"
  179. })), needsScrollbar(swiperParams) && /*#__PURE__*/React.createElement("div", {
  180. ref: scrollbarElRef,
  181. className: "swiper-scrollbar"
  182. }), needsPagination(swiperParams) && /*#__PURE__*/React.createElement("div", {
  183. ref: paginationElRef,
  184. className: "swiper-pagination"
  185. }), slots['container-end']));
  186. });
  187. Swiper.displayName = 'Swiper';
  188. export { Swiper };