swiper.svelte 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. <script>
  2. import { onMount, onDestroy, afterUpdate, createEventDispatcher, tick, setContext } from 'svelte';
  3. import Swiper from 'swiper';
  4. import { getParams } from '../components-shared/get-params.js';
  5. import { mountSwiper } from '../components-shared/mount-swiper.js';
  6. import {
  7. needsScrollbar,
  8. needsNavigation,
  9. needsPagination,
  10. uniqueClasses,
  11. extend,
  12. } from '../components-shared/utils.js';
  13. import { getChangedParams } from '../components-shared/get-changed-params.js';
  14. import { updateSwiper } from '../components-shared/update-swiper.js';
  15. const dispatch = createEventDispatcher();
  16. let className = undefined;
  17. export { className as class };
  18. export let tag = 'div';
  19. export let wrapperTag = 'div';
  20. let containerClasses = 'swiper';
  21. let breakpointChanged = false;
  22. let swiperInstance = null;
  23. let oldPassedParams = null;
  24. let paramsData;
  25. let swiperParams;
  26. let passedParams;
  27. let restProps;
  28. let swiperEl = null;
  29. let prevEl = null;
  30. let nextEl = null;
  31. let scrollbarEl = null;
  32. let paginationEl = null;
  33. let virtualData = { slides: [] };
  34. export function swiper() {
  35. return swiperInstance;
  36. }
  37. const setVirtualData = (data) => {
  38. virtualData = data;
  39. tick().then(() => {
  40. swiperInstance.$wrapperEl.children('.swiper-slide').each((el) => {
  41. if (el.onSwiper) el.onSwiper(swiperInstance);
  42. });
  43. swiperInstance.updateSlides();
  44. swiperInstance.updateProgress();
  45. swiperInstance.updateSlidesClasses();
  46. if (swiperInstance.lazy && swiperInstance.params.lazy.enabled) {
  47. swiperInstance.lazy.load();
  48. }
  49. });
  50. };
  51. const calcParams = () => {
  52. paramsData = getParams($$restProps);
  53. swiperParams = paramsData.params;
  54. passedParams = paramsData.passedParams;
  55. restProps = paramsData.rest;
  56. };
  57. calcParams();
  58. oldPassedParams = passedParams;
  59. const onBeforeBreakpoint = () => {
  60. breakpointChanged = true;
  61. };
  62. swiperParams.onAny = (event, ...args) => {
  63. dispatch(event, args);
  64. };
  65. Object.assign(swiperParams.on, {
  66. _beforeBreakpoint: onBeforeBreakpoint,
  67. _containerClasses(_swiper, classes) {
  68. containerClasses = classes;
  69. },
  70. });
  71. swiperInstance = new Swiper(swiperParams);
  72. setContext('swiper', swiperInstance);
  73. if (swiperInstance.virtual && swiperInstance.params.virtual.enabled) {
  74. const extendWith = {
  75. cache: false,
  76. renderExternal: (data) => {
  77. setVirtualData(data);
  78. if (swiperParams.virtual && swiperParams.virtual.renderExternal) {
  79. swiperParams.virtual.renderExternal(data);
  80. }
  81. },
  82. renderExternalUpdate: false,
  83. };
  84. extend(swiperInstance.params.virtual, extendWith);
  85. extend(swiperInstance.originalParams.virtual, extendWith);
  86. }
  87. onMount(() => {
  88. if (!swiperEl) return;
  89. mountSwiper(
  90. {
  91. el: swiperEl,
  92. nextEl: nextEl,
  93. prevEl: prevEl,
  94. paginationEl: paginationEl,
  95. scrollbarEl: scrollbarEl,
  96. swiper: swiperInstance,
  97. },
  98. swiperParams,
  99. );
  100. dispatch('swiper', [swiperInstance]);
  101. if (swiperParams.virtual) return;
  102. swiperInstance.slides.each((el) => {
  103. if (el.onSwiper) el.onSwiper(swiperInstance);
  104. });
  105. });
  106. afterUpdate(() => {
  107. if (!swiperInstance) return;
  108. calcParams();
  109. const changedParams = getChangedParams(passedParams, oldPassedParams);
  110. if (
  111. (changedParams.length || breakpointChanged) &&
  112. swiperInstance &&
  113. !swiperInstance.destroyed
  114. ) {
  115. updateSwiper({
  116. swiper: swiperInstance,
  117. passedParams,
  118. changedParams,
  119. nextEl,
  120. prevEl,
  121. scrollbarEl,
  122. paginationEl,
  123. });
  124. }
  125. breakpointChanged = false;
  126. oldPassedParams = passedParams;
  127. });
  128. onDestroy(() => {
  129. // eslint-disable-next-line
  130. if (typeof window !== 'undefined' && swiperInstance && !swiperInstance.destroyed) {
  131. swiperInstance.destroy(true, false);
  132. }
  133. });
  134. </script>
  135. <svelte:element
  136. this={tag}
  137. bind:this={swiperEl}
  138. class={uniqueClasses(`${containerClasses}${className ? ` ${className}` : ''}`)}
  139. {...restProps}
  140. >
  141. <slot name="container-start" />
  142. <svelte:element this={wrapperTag} class="swiper-wrapper">
  143. <slot name="wrapper-start" />
  144. <slot {virtualData} />
  145. <slot name="wrapper-end" />
  146. </svelte:element>
  147. {#if needsNavigation(swiperParams)}
  148. <div bind:this={prevEl} class="swiper-button-prev" />
  149. <div bind:this={nextEl} class="swiper-button-next" />
  150. {/if}
  151. {#if needsScrollbar(swiperParams)}
  152. <div bind:this={scrollbarEl} class="swiper-scrollbar" />
  153. {/if}
  154. {#if needsPagination(swiperParams)}
  155. <div bind:this={paginationEl} class="swiper-pagination" />
  156. {/if}
  157. <slot name="container-end" />
  158. </svelte:element>