swiper.js 16 KB

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