swiper.js 6.9 KB

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