swiper.js 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664
  1. import { h, ref, onMounted, onUpdated, onBeforeUnmount, watch, nextTick, provide } from 'vue';
  2. import SwiperCore from 'swiper';
  3. import { getParams } from '../components-shared/get-params.js';
  4. import { mountSwiper } from '../components-shared/mount-swiper.js';
  5. import { needsScrollbar, needsNavigation, needsPagination, uniqueClasses, extend } from '../components-shared/utils.js';
  6. import { renderLoop, calcLoopedSlides } from './loop.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. const Swiper = {
  13. name: 'Swiper',
  14. props: {
  15. tag: {
  16. type: String,
  17. default: 'div'
  18. },
  19. wrapperTag: {
  20. type: String,
  21. default: 'div'
  22. },
  23. modules: {
  24. type: Array,
  25. default: undefined
  26. },
  27. init: {
  28. type: Boolean,
  29. default: undefined
  30. },
  31. direction: {
  32. type: String,
  33. default: undefined
  34. },
  35. touchEventsTarget: {
  36. type: String,
  37. default: undefined
  38. },
  39. initialSlide: {
  40. type: Number,
  41. default: undefined
  42. },
  43. speed: {
  44. type: Number,
  45. default: undefined
  46. },
  47. cssMode: {
  48. type: Boolean,
  49. default: undefined
  50. },
  51. updateOnWindowResize: {
  52. type: Boolean,
  53. default: undefined
  54. },
  55. resizeObserver: {
  56. type: Boolean,
  57. default: undefined
  58. },
  59. nested: {
  60. type: Boolean,
  61. default: undefined
  62. },
  63. focusableElements: {
  64. type: String,
  65. default: undefined
  66. },
  67. width: {
  68. type: Number,
  69. default: undefined
  70. },
  71. height: {
  72. type: Number,
  73. default: undefined
  74. },
  75. preventInteractionOnTransition: {
  76. type: Boolean,
  77. default: undefined
  78. },
  79. userAgent: {
  80. type: String,
  81. default: undefined
  82. },
  83. url: {
  84. type: String,
  85. default: undefined
  86. },
  87. edgeSwipeDetection: {
  88. type: [Boolean, String],
  89. default: undefined
  90. },
  91. edgeSwipeThreshold: {
  92. type: Number,
  93. default: undefined
  94. },
  95. autoHeight: {
  96. type: Boolean,
  97. default: undefined
  98. },
  99. setWrapperSize: {
  100. type: Boolean,
  101. default: undefined
  102. },
  103. virtualTranslate: {
  104. type: Boolean,
  105. default: undefined
  106. },
  107. effect: {
  108. type: String,
  109. default: undefined
  110. },
  111. breakpoints: {
  112. type: Object,
  113. default: undefined
  114. },
  115. spaceBetween: {
  116. type: Number,
  117. default: undefined
  118. },
  119. slidesPerView: {
  120. type: [Number, String],
  121. default: undefined
  122. },
  123. maxBackfaceHiddenSlides: {
  124. type: Number,
  125. default: undefined
  126. },
  127. slidesPerGroup: {
  128. type: Number,
  129. default: undefined
  130. },
  131. slidesPerGroupSkip: {
  132. type: Number,
  133. default: undefined
  134. },
  135. slidesPerGroupAuto: {
  136. type: Boolean,
  137. default: undefined
  138. },
  139. centeredSlides: {
  140. type: Boolean,
  141. default: undefined
  142. },
  143. centeredSlidesBounds: {
  144. type: Boolean,
  145. default: undefined
  146. },
  147. slidesOffsetBefore: {
  148. type: Number,
  149. default: undefined
  150. },
  151. slidesOffsetAfter: {
  152. type: Number,
  153. default: undefined
  154. },
  155. normalizeSlideIndex: {
  156. type: Boolean,
  157. default: undefined
  158. },
  159. centerInsufficientSlides: {
  160. type: Boolean,
  161. default: undefined
  162. },
  163. watchOverflow: {
  164. type: Boolean,
  165. default: undefined
  166. },
  167. roundLengths: {
  168. type: Boolean,
  169. default: undefined
  170. },
  171. touchRatio: {
  172. type: Number,
  173. default: undefined
  174. },
  175. touchAngle: {
  176. type: Number,
  177. default: undefined
  178. },
  179. simulateTouch: {
  180. type: Boolean,
  181. default: undefined
  182. },
  183. shortSwipes: {
  184. type: Boolean,
  185. default: undefined
  186. },
  187. longSwipes: {
  188. type: Boolean,
  189. default: undefined
  190. },
  191. longSwipesRatio: {
  192. type: Number,
  193. default: undefined
  194. },
  195. longSwipesMs: {
  196. type: Number,
  197. default: undefined
  198. },
  199. followFinger: {
  200. type: Boolean,
  201. default: undefined
  202. },
  203. allowTouchMove: {
  204. type: Boolean,
  205. default: undefined
  206. },
  207. threshold: {
  208. type: Number,
  209. default: undefined
  210. },
  211. touchMoveStopPropagation: {
  212. type: Boolean,
  213. default: undefined
  214. },
  215. touchStartPreventDefault: {
  216. type: Boolean,
  217. default: undefined
  218. },
  219. touchStartForcePreventDefault: {
  220. type: Boolean,
  221. default: undefined
  222. },
  223. touchReleaseOnEdges: {
  224. type: Boolean,
  225. default: undefined
  226. },
  227. uniqueNavElements: {
  228. type: Boolean,
  229. default: undefined
  230. },
  231. resistance: {
  232. type: Boolean,
  233. default: undefined
  234. },
  235. resistanceRatio: {
  236. type: Number,
  237. default: undefined
  238. },
  239. watchSlidesProgress: {
  240. type: Boolean,
  241. default: undefined
  242. },
  243. grabCursor: {
  244. type: Boolean,
  245. default: undefined
  246. },
  247. preventClicks: {
  248. type: Boolean,
  249. default: undefined
  250. },
  251. preventClicksPropagation: {
  252. type: Boolean,
  253. default: undefined
  254. },
  255. slideToClickedSlide: {
  256. type: Boolean,
  257. default: undefined
  258. },
  259. preloadImages: {
  260. type: Boolean,
  261. default: undefined
  262. },
  263. updateOnImagesReady: {
  264. type: Boolean,
  265. default: undefined
  266. },
  267. loop: {
  268. type: Boolean,
  269. default: undefined
  270. },
  271. loopAdditionalSlides: {
  272. type: Number,
  273. default: undefined
  274. },
  275. loopedSlides: {
  276. type: Number,
  277. default: undefined
  278. },
  279. loopedSlidesLimit: {
  280. type: Boolean,
  281. default: true
  282. },
  283. loopFillGroupWithBlank: {
  284. type: Boolean,
  285. default: undefined
  286. },
  287. loopPreventsSlide: {
  288. type: Boolean,
  289. default: undefined
  290. },
  291. rewind: {
  292. type: Boolean,
  293. default: undefined
  294. },
  295. allowSlidePrev: {
  296. type: Boolean,
  297. default: undefined
  298. },
  299. allowSlideNext: {
  300. type: Boolean,
  301. default: undefined
  302. },
  303. swipeHandler: {
  304. type: Boolean,
  305. default: undefined
  306. },
  307. noSwiping: {
  308. type: Boolean,
  309. default: undefined
  310. },
  311. noSwipingClass: {
  312. type: String,
  313. default: undefined
  314. },
  315. noSwipingSelector: {
  316. type: String,
  317. default: undefined
  318. },
  319. passiveListeners: {
  320. type: Boolean,
  321. default: undefined
  322. },
  323. containerModifierClass: {
  324. type: String,
  325. default: undefined
  326. },
  327. slideClass: {
  328. type: String,
  329. default: undefined
  330. },
  331. slideBlankClass: {
  332. type: String,
  333. default: undefined
  334. },
  335. slideActiveClass: {
  336. type: String,
  337. default: undefined
  338. },
  339. slideDuplicateActiveClass: {
  340. type: String,
  341. default: undefined
  342. },
  343. slideVisibleClass: {
  344. type: String,
  345. default: undefined
  346. },
  347. slideDuplicateClass: {
  348. type: String,
  349. default: undefined
  350. },
  351. slideNextClass: {
  352. type: String,
  353. default: undefined
  354. },
  355. slideDuplicateNextClass: {
  356. type: String,
  357. default: undefined
  358. },
  359. slidePrevClass: {
  360. type: String,
  361. default: undefined
  362. },
  363. slideDuplicatePrevClass: {
  364. type: String,
  365. default: undefined
  366. },
  367. wrapperClass: {
  368. type: String,
  369. default: undefined
  370. },
  371. runCallbacksOnInit: {
  372. type: Boolean,
  373. default: undefined
  374. },
  375. observer: {
  376. type: Boolean,
  377. default: undefined
  378. },
  379. observeParents: {
  380. type: Boolean,
  381. default: undefined
  382. },
  383. observeSlideChildren: {
  384. type: Boolean,
  385. default: undefined
  386. },
  387. a11y: {
  388. type: [Boolean, Object],
  389. default: undefined
  390. },
  391. autoplay: {
  392. type: [Boolean, Object],
  393. default: undefined
  394. },
  395. controller: {
  396. type: Object,
  397. default: undefined
  398. },
  399. coverflowEffect: {
  400. type: Object,
  401. default: undefined
  402. },
  403. cubeEffect: {
  404. type: Object,
  405. default: undefined
  406. },
  407. fadeEffect: {
  408. type: Object,
  409. default: undefined
  410. },
  411. flipEffect: {
  412. type: Object,
  413. default: undefined
  414. },
  415. creativeEffect: {
  416. type: Object,
  417. default: undefined
  418. },
  419. cardsEffect: {
  420. type: Object,
  421. default: undefined
  422. },
  423. hashNavigation: {
  424. type: [Boolean, Object],
  425. default: undefined
  426. },
  427. history: {
  428. type: [Boolean, Object],
  429. default: undefined
  430. },
  431. keyboard: {
  432. type: [Boolean, Object],
  433. default: undefined
  434. },
  435. lazy: {
  436. type: [Boolean, Object],
  437. default: undefined
  438. },
  439. mousewheel: {
  440. type: [Boolean, Object],
  441. default: undefined
  442. },
  443. navigation: {
  444. type: [Boolean, Object],
  445. default: undefined
  446. },
  447. pagination: {
  448. type: [Boolean, Object],
  449. default: undefined
  450. },
  451. parallax: {
  452. type: [Boolean, Object],
  453. default: undefined
  454. },
  455. scrollbar: {
  456. type: [Boolean, Object],
  457. default: undefined
  458. },
  459. thumbs: {
  460. type: Object,
  461. default: undefined
  462. },
  463. virtual: {
  464. type: [Boolean, Object],
  465. default: undefined
  466. },
  467. zoom: {
  468. type: [Boolean, Object],
  469. default: undefined
  470. },
  471. grid: {
  472. type: [Object],
  473. default: undefined
  474. },
  475. freeMode: {
  476. type: [Boolean, Object],
  477. default: undefined
  478. },
  479. enabled: {
  480. type: Boolean,
  481. default: undefined
  482. }
  483. },
  484. emits: ['_beforeBreakpoint', '_containerClasses', '_slideClass', '_slideClasses', '_swiper', '_freeModeNoMomentumRelease', 'activeIndexChange', 'afterInit', 'autoplay', 'autoplayStart', 'autoplayStop', 'autoplayPause', 'autoplayResume', 'beforeDestroy', 'beforeInit', 'beforeLoopFix', 'beforeResize', 'beforeSlideChangeStart', 'beforeTransitionStart', 'breakpoint', 'changeDirection', 'click', 'disable', 'doubleTap', 'doubleClick', 'destroy', 'enable', 'fromEdge', 'hashChange', 'hashSet', 'imagesReady', 'init', 'keyPress', 'lazyImageLoad', 'lazyImageReady', 'lock', 'loopFix', 'momentumBounce', 'navigationHide', 'navigationShow', 'navigationPrev', 'navigationNext', 'observerUpdate', 'orientationchange', 'paginationHide', 'paginationRender', 'paginationShow', 'paginationUpdate', 'progress', 'reachBeginning', 'reachEnd', 'realIndexChange', 'resize', 'scroll', 'scrollbarDragEnd', 'scrollbarDragMove', 'scrollbarDragStart', 'setTransition', 'setTranslate', 'slideChange', 'slideChangeTransitionEnd', 'slideChangeTransitionStart', 'slideNextTransitionEnd', 'slideNextTransitionStart', 'slidePrevTransitionEnd', 'slidePrevTransitionStart', 'slideResetTransitionStart', 'slideResetTransitionEnd', 'sliderMove', 'sliderFirstMove', 'slidesLengthChange', 'slidesGridLengthChange', 'snapGridLengthChange', 'snapIndexChange', 'swiper', 'tap', 'toEdge', 'touchEnd', 'touchMove', 'touchMoveOpposite', 'touchStart', 'transitionEnd', 'transitionStart', 'unlock', 'update', 'virtualUpdate', 'zoomChange'],
  485. setup(props, _ref) {
  486. let {
  487. slots: originalSlots,
  488. emit
  489. } = _ref;
  490. const {
  491. tag: Tag,
  492. wrapperTag: WrapperTag
  493. } = props;
  494. const containerClasses = ref('swiper');
  495. const virtualData = ref(null);
  496. const breakpointChanged = ref(false);
  497. const initializedRef = ref(false);
  498. const swiperElRef = ref(null);
  499. const swiperRef = ref(null);
  500. const oldPassedParamsRef = ref(null);
  501. const slidesRef = {
  502. value: []
  503. };
  504. const oldSlidesRef = {
  505. value: []
  506. };
  507. const nextElRef = ref(null);
  508. const prevElRef = ref(null);
  509. const paginationElRef = ref(null);
  510. const scrollbarElRef = ref(null);
  511. const {
  512. params: swiperParams,
  513. passedParams
  514. } = getParams(props, false);
  515. getChildren(originalSlots, slidesRef, oldSlidesRef);
  516. oldPassedParamsRef.value = passedParams;
  517. oldSlidesRef.value = slidesRef.value;
  518. const onBeforeBreakpoint = () => {
  519. getChildren(originalSlots, slidesRef, oldSlidesRef);
  520. breakpointChanged.value = true;
  521. };
  522. swiperParams.onAny = function (event) {
  523. for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
  524. args[_key - 1] = arguments[_key];
  525. }
  526. emit(event, ...args);
  527. };
  528. Object.assign(swiperParams.on, {
  529. _beforeBreakpoint: onBeforeBreakpoint,
  530. _containerClasses(swiper, classes) {
  531. containerClasses.value = classes;
  532. }
  533. }); // init Swiper
  534. swiperRef.value = new SwiperCore(swiperParams);
  535. swiperRef.value.loopCreate = () => {};
  536. swiperRef.value.loopDestroy = () => {};
  537. if (swiperParams.loop) {
  538. swiperRef.value.loopedSlides = calcLoopedSlides(slidesRef.value, swiperParams);
  539. }
  540. if (swiperRef.value.virtual && swiperRef.value.params.virtual.enabled) {
  541. swiperRef.value.virtual.slides = slidesRef.value;
  542. const extendWith = {
  543. cache: false,
  544. slides: slidesRef.value,
  545. renderExternal: data => {
  546. virtualData.value = data;
  547. },
  548. renderExternalUpdate: false
  549. };
  550. extend(swiperRef.value.params.virtual, extendWith);
  551. extend(swiperRef.value.originalParams.virtual, extendWith);
  552. }
  553. onUpdated(() => {
  554. // set initialized flag
  555. if (!initializedRef.value && swiperRef.value) {
  556. swiperRef.value.emitSlidesClasses();
  557. initializedRef.value = true;
  558. } // watch for params change
  559. const {
  560. passedParams: newPassedParams
  561. } = getParams(props, false);
  562. const changedParams = getChangedParams(newPassedParams, oldPassedParamsRef.value, slidesRef.value, oldSlidesRef.value, c => c.props && c.props.key);
  563. oldPassedParamsRef.value = newPassedParams;
  564. if ((changedParams.length || breakpointChanged.value) && swiperRef.value && !swiperRef.value.destroyed) {
  565. updateSwiper({
  566. swiper: swiperRef.value,
  567. slides: slidesRef.value,
  568. passedParams: newPassedParams,
  569. changedParams,
  570. nextEl: nextElRef.value,
  571. prevEl: prevElRef.value,
  572. scrollbarEl: scrollbarElRef.value,
  573. paginationEl: paginationElRef.value
  574. });
  575. }
  576. breakpointChanged.value = false;
  577. });
  578. provide('swiper', swiperRef); // update on virtual update
  579. watch(virtualData, () => {
  580. nextTick(() => {
  581. updateOnVirtualData(swiperRef.value);
  582. });
  583. }); // mount swiper
  584. onMounted(() => {
  585. if (!swiperElRef.value) return;
  586. mountSwiper({
  587. el: swiperElRef.value,
  588. nextEl: nextElRef.value,
  589. prevEl: prevElRef.value,
  590. paginationEl: paginationElRef.value,
  591. scrollbarEl: scrollbarElRef.value,
  592. swiper: swiperRef.value
  593. }, swiperParams);
  594. emit('swiper', swiperRef.value);
  595. });
  596. onBeforeUnmount(() => {
  597. if (swiperRef.value && !swiperRef.value.destroyed) {
  598. swiperRef.value.destroy(true, false);
  599. }
  600. }); // bypass swiper instance to slides
  601. function renderSlides(slides) {
  602. if (swiperParams.virtual) {
  603. return renderVirtual(swiperRef, slides, virtualData.value);
  604. }
  605. if (!swiperParams.loop || swiperRef.value && swiperRef.value.destroyed) {
  606. slides.forEach(slide => {
  607. if (!slide.props) slide.props = {};
  608. slide.props.swiperRef = swiperRef;
  609. });
  610. return slides;
  611. }
  612. return renderLoop(swiperRef, slides, swiperParams);
  613. }
  614. return () => {
  615. const {
  616. slides,
  617. slots
  618. } = getChildren(originalSlots, slidesRef, oldSlidesRef);
  619. return h(Tag, {
  620. ref: swiperElRef,
  621. class: uniqueClasses(containerClasses.value)
  622. }, [slots['container-start'], h(WrapperTag, {
  623. class: 'swiper-wrapper'
  624. }, [slots['wrapper-start'], renderSlides(slides), slots['wrapper-end']]), needsNavigation(props) && [h('div', {
  625. ref: prevElRef,
  626. class: 'swiper-button-prev'
  627. }), h('div', {
  628. ref: nextElRef,
  629. class: 'swiper-button-next'
  630. })], needsScrollbar(props) && h('div', {
  631. ref: scrollbarElRef,
  632. class: 'swiper-scrollbar'
  633. }), needsPagination(props) && h('div', {
  634. ref: paginationElRef,
  635. class: 'swiper-pagination'
  636. }), slots['container-end']]);
  637. };
  638. }
  639. };
  640. export { Swiper };