swiper.js 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  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, wrapperClass } from '../components-shared/utils.js';
  7. import { getChangedParams } from '../components-shared/get-changed-params.js';
  8. import { getChildren } from './get-children.js';
  9. import { updateSwiper } from '../components-shared/update-swiper.js';
  10. import { renderVirtual } from './virtual.js';
  11. import { updateOnVirtualData } from '../components-shared/update-on-virtual-data.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. const passParams = {
  59. ...swiperParams
  60. };
  61. delete passParams.wrapperClass;
  62. swiperRef.current = new SwiperCore(passParams);
  63. if (swiperRef.current.virtual && swiperRef.current.params.virtual.enabled) {
  64. swiperRef.current.virtual.slides = slides;
  65. const extendWith = {
  66. cache: false,
  67. slides,
  68. renderExternal: setVirtualData,
  69. renderExternalUpdate: false
  70. };
  71. extend(swiperRef.current.params.virtual, extendWith);
  72. extend(swiperRef.current.originalParams.virtual, extendWith);
  73. }
  74. };
  75. if (!swiperElRef.current) {
  76. initSwiper();
  77. }
  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. });
  99. // set initialized flag
  100. useEffect(() => {
  101. if (!initializedRef.current && swiperRef.current) {
  102. swiperRef.current.emitSlidesClasses();
  103. initializedRef.current = true;
  104. }
  105. });
  106. // mount swiper
  107. useIsomorphicLayoutEffect(() => {
  108. if (externalElRef) {
  109. externalElRef.current = swiperElRef.current;
  110. }
  111. if (!swiperElRef.current) return;
  112. if (swiperRef.current.destroyed) {
  113. initSwiper();
  114. }
  115. mountSwiper({
  116. el: swiperElRef.current,
  117. nextEl: nextElRef.current,
  118. prevEl: prevElRef.current,
  119. paginationEl: paginationElRef.current,
  120. scrollbarEl: scrollbarElRef.current,
  121. swiper: swiperRef.current
  122. }, swiperParams);
  123. if (onSwiper) onSwiper(swiperRef.current);
  124. // eslint-disable-next-line
  125. return () => {
  126. if (swiperRef.current && !swiperRef.current.destroyed) {
  127. swiperRef.current.destroy(true, false);
  128. }
  129. };
  130. }, []);
  131. // watch for params change
  132. useIsomorphicLayoutEffect(() => {
  133. attachEvents();
  134. const changedParams = getChangedParams(passedParams, oldPassedParamsRef.current, slides, oldSlides.current, c => c.key);
  135. oldPassedParamsRef.current = passedParams;
  136. oldSlides.current = slides;
  137. if (changedParams.length && swiperRef.current && !swiperRef.current.destroyed) {
  138. updateSwiper({
  139. swiper: swiperRef.current,
  140. slides,
  141. passedParams,
  142. changedParams,
  143. nextEl: nextElRef.current,
  144. prevEl: prevElRef.current,
  145. scrollbarEl: scrollbarElRef.current,
  146. paginationEl: paginationElRef.current
  147. });
  148. }
  149. return () => {
  150. detachEvents();
  151. };
  152. });
  153. // update on virtual update
  154. useIsomorphicLayoutEffect(() => {
  155. updateOnVirtualData(swiperRef.current);
  156. }, [virtualData]);
  157. // bypass swiper instance to slides
  158. function renderSlides() {
  159. if (swiperParams.virtual) {
  160. return renderVirtual(swiperRef.current, slides, virtualData);
  161. }
  162. return slides.map((child, index) => {
  163. return /*#__PURE__*/React.cloneElement(child, {
  164. swiper: swiperRef.current,
  165. swiperSlideIndex: index
  166. });
  167. });
  168. }
  169. return /*#__PURE__*/React.createElement(Tag, _extends({
  170. ref: swiperElRef,
  171. className: uniqueClasses(`${containerClasses}${className ? ` ${className}` : ''}`)
  172. }, restProps), /*#__PURE__*/React.createElement(SwiperContext.Provider, {
  173. value: swiperRef.current
  174. }, slots['container-start'], /*#__PURE__*/React.createElement(WrapperTag, {
  175. className: wrapperClass(swiperParams.wrapperClass)
  176. }, slots['wrapper-start'], renderSlides(), slots['wrapper-end']), needsNavigation(swiperParams) && /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("div", {
  177. ref: prevElRef,
  178. className: "swiper-button-prev"
  179. }), /*#__PURE__*/React.createElement("div", {
  180. ref: nextElRef,
  181. className: "swiper-button-next"
  182. })), needsScrollbar(swiperParams) && /*#__PURE__*/React.createElement("div", {
  183. ref: scrollbarElRef,
  184. className: "swiper-scrollbar"
  185. }), needsPagination(swiperParams) && /*#__PURE__*/React.createElement("div", {
  186. ref: paginationElRef,
  187. className: "swiper-pagination"
  188. }), slots['container-end']));
  189. });
  190. Swiper.displayName = 'Swiper';
  191. export { Swiper };