pagination.js 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510
  1. import classesToSelector from '../../shared/classes-to-selector.js';
  2. export default function Pagination({
  3. swiper,
  4. extendParams,
  5. on,
  6. emit
  7. }) {
  8. const pfx = 'swiper-pagination';
  9. extendParams({
  10. pagination: {
  11. el: null,
  12. bulletElement: 'span',
  13. clickable: false,
  14. hideOnClick: false,
  15. renderBullet: null,
  16. renderProgressbar: null,
  17. renderFraction: null,
  18. renderCustom: null,
  19. progressbarOpposite: false,
  20. type: 'bullets', // 'bullets' or 'progressbar' or 'fraction' or 'custom'
  21. dynamicBullets: false,
  22. dynamicMainBullets: 1,
  23. formatFractionCurrent: (number) => number,
  24. formatFractionTotal: (number) => number,
  25. bulletClass: `${pfx}-bullet`,
  26. bulletActiveClass: `${pfx}-bullet-active`,
  27. modifierClass: `${pfx}-`,
  28. currentClass: `${pfx}-current`,
  29. totalClass: `${pfx}-total`,
  30. hiddenClass: `${pfx}-hidden`,
  31. progressbarFillClass: `${pfx}-progressbar-fill`,
  32. progressbarOppositeClass: `${pfx}-progressbar-opposite`,
  33. clickableClass: `${pfx}-clickable`,
  34. lockClass: `${pfx}-lock`,
  35. horizontalClass: `${pfx}-horizontal`,
  36. verticalClass: `${pfx}-vertical`,
  37. },
  38. });
  39. swiper.pagination = {
  40. el: null,
  41. $el: null,
  42. bullets: [],
  43. };
  44. let bulletSize;
  45. let dynamicBulletIndex = 0;
  46. function isPaginationDisabled() {
  47. return (
  48. !swiper.params.pagination.el ||
  49. !swiper.pagination.el ||
  50. !swiper.pagination.$el
  51. );
  52. }
  53. function setSideBullets($bulletEl, position) {
  54. const {
  55. bulletActiveClass
  56. } = swiper.params.pagination;
  57. const bullets = swiper.pagination.bullets;
  58. if (bullets[$bulletEl.index + position]) {
  59. bullets[$bulletEl.index + position].addPaginationItemClass(
  60. `${bulletActiveClass}-${position>0?'next':'prev'}`);
  61. }
  62. if (bullets[$bulletEl.index + (position > 0 ? position + 1 : position -
  63. 1)]) {
  64. bullets[$bulletEl.index + (position > 0 ? position + 1 : position - 1)].addPaginationItemClass(
  65. `${bulletActiveClass}-${position>0?'next':'prev'}-${position>0?'next':'prev'}`);
  66. }
  67. }
  68. function update() {
  69. // Render || Update Pagination bullets/items
  70. const rtl = swiper.rtl;
  71. const params = swiper.params.pagination;
  72. if (isPaginationDisabled()) return;
  73. const slidesLength =
  74. swiper.virtual && swiper.params.virtual.enabled ?
  75. swiper.virtual.slides.length :
  76. swiper.slides.length;
  77. const $el = swiper.pagination.$el;
  78. // Current/Total
  79. let current;
  80. const total = swiper.params.loop ?
  81. Math.ceil((slidesLength - swiper.loopedSlides * 2) / swiper.params.slidesPerGroup) :
  82. swiper.snapGrid.length;
  83. if (swiper.params.loop) {
  84. current = Math.ceil(
  85. (swiper.activeIndex - swiper.loopedSlides) / swiper.params.slidesPerGroup,
  86. );
  87. if (current > slidesLength - 1 - swiper.loopedSlides * 2) {
  88. current -= slidesLength - swiper.loopedSlides * 2;
  89. }
  90. if (current > total - 1) current -= total;
  91. if (current < 0 && swiper.params.paginationType !== 'bullets') current = total + current;
  92. } else if (typeof swiper.snapIndex !== 'undefined') {
  93. current = swiper.snapIndex;
  94. } else {
  95. current = swiper.activeIndex || 0;
  96. }
  97. // Types
  98. if (
  99. params.type === 'bullets' &&
  100. swiper.pagination.bullets &&
  101. swiper.pagination.bullets.length > 0
  102. ) {
  103. const bullets = swiper.pagination.bullets;
  104. let firstIndex;
  105. let lastIndex;
  106. let midIndex;
  107. if (params.dynamicBullets) {
  108. bulletSize = bullets[0][swiper.isHorizontal() ? 'outerWidth' : 'outerHeight'];
  109. swiper.$wrapperEl.paginationCss({
  110. [swiper.isHorizontal() ? 'width' :
  111. 'height'
  112. ]: `${bulletSize * (params.dynamicMainBullets + 4)}px`
  113. });
  114. if (params.dynamicMainBullets > 1 && swiper.previousIndex !== undefined) {
  115. dynamicBulletIndex += current - (swiper.previousIndex - swiper.loopedSlides || 0);
  116. if (dynamicBulletIndex > params.dynamicMainBullets - 1) {
  117. dynamicBulletIndex = params.dynamicMainBullets - 1;
  118. } else if (dynamicBulletIndex < 0) {
  119. dynamicBulletIndex = 0;
  120. }
  121. }
  122. firstIndex = Math.max(current - dynamicBulletIndex, 0);
  123. lastIndex = firstIndex + (Math.min(bullets.length, params.dynamicMainBullets) - 1);
  124. midIndex = (lastIndex + firstIndex) / 2;
  125. }
  126. bullets.forEach((item) => {
  127. item.removePaginationItemClass(
  128. ['', '-next', '-next-next', '-prev', '-prev-prev', '-main']
  129. .map((suffix) => `${params.bulletActiveClass}${suffix}`)
  130. .join(' '),
  131. );
  132. })
  133. if ($el.length > 1) {
  134. bullets.each((bullet) => {
  135. const $bullet = $(bullet);
  136. const bulletIndex = $bullet.index();
  137. if (bulletIndex === current) {
  138. $bullet.addClass(params.bulletActiveClass);
  139. }
  140. if (params.dynamicBullets) {
  141. if (bulletIndex >= firstIndex && bulletIndex <= lastIndex) {
  142. $bullet.addClass(`${params.bulletActiveClass}-main`);
  143. }
  144. if (bulletIndex === firstIndex) {
  145. setSideBullets($bullet, 'prev');
  146. }
  147. if (bulletIndex === lastIndex) {
  148. setSideBullets($bullet, 'next');
  149. }
  150. }
  151. });
  152. } else {
  153. const $bullet = bullets[current];
  154. const bulletIndex = $bullet.index;
  155. $bullet.addPaginationItemClass(params.bulletActiveClass);
  156. if (params.dynamicBullets) {
  157. const $firstDisplayedBullet = bullets[firstIndex];
  158. const $lastDisplayedBullet = bullets[lastIndex];
  159. for (let i = firstIndex; i <= lastIndex; i += 1) {
  160. bullets[i].addPaginationItemClass(`${params.bulletActiveClass}-main`);
  161. }
  162. if (swiper.params.loop) {
  163. if (bulletIndex >= bullets.length) {
  164. for (let i = params.dynamicMainBullets; i >= 0; i -= 1) {
  165. bullets[bullets.length - i].addPaginationItemClass(`${params.bulletActiveClass}-main`);
  166. }
  167. bullets
  168. [bullets.length - params.dynamicMainBullets - 1]
  169. .addPaginationItemClass(`${params.bulletActiveClass}-prev`);
  170. } else {
  171. setSideBullets($firstDisplayedBullet, -1);
  172. setSideBullets($lastDisplayedBullet, 1);
  173. }
  174. } else {
  175. setSideBullets($firstDisplayedBullet, -1);
  176. setSideBullets($lastDisplayedBullet, 1);
  177. }
  178. }
  179. }
  180. if (params.dynamicBullets) {
  181. const dynamicBulletsLength = Math.min(bullets.length, params.dynamicMainBullets + 4);
  182. const bulletsOffset =
  183. (bulletSize * dynamicBulletsLength - bulletSize) / 2 - midIndex * bulletSize;
  184. const offsetProp = rtl ? 'right' : 'left';
  185. bullets.forEach((item) => {
  186. item.setCss({
  187. [swiper.isHorizontal() ? offsetProp : 'top']: `${bulletsOffset}px`
  188. })
  189. })
  190. // bullets.css(swiper.isHorizontal() ? offsetProp : 'top', `${bulletsOffset}px`);
  191. }
  192. }
  193. if (params.type === 'fraction') {
  194. // $el
  195. // .find(classesToSelector(params.currentClass))
  196. // .text(params.formatFractionCurrent(current + 1));
  197. swiper.native.paginationContent.text = params.formatFractionCurrent(current + 1);
  198. swiper.native.paginationContent.total = params.formatFractionTotal(total);
  199. swiper.native.updateData({
  200. paginationContent: swiper.native.paginationContent,
  201. })
  202. // $el.find(classesToSelector(params.totalClass)).text(params.formatFractionTotal(total));
  203. }
  204. if (params.type === 'progressbar') {
  205. let progressbarDirection;
  206. if (params.progressbarOpposite) {
  207. progressbarDirection = swiper.isHorizontal() ? 'vertical' : 'horizontal';
  208. } else {
  209. progressbarDirection = swiper.isHorizontal() ? 'horizontal' : 'vertical';
  210. }
  211. const scale = (current + 1) / total;
  212. let scaleX = 1;
  213. let scaleY = 1;
  214. if (progressbarDirection === 'horizontal') {
  215. scaleX = scale;
  216. } else {
  217. scaleY = scale;
  218. }
  219. // $el
  220. // .find(classesToSelector(params.progressbarFillClass))
  221. swiper.native.paginationContent.transform(`translate3d(0,0,0) scaleX(${scaleX}) scaleY(${scaleY})`);
  222. swiper.native.paginationContent.transition(swiper.params.speed);
  223. swiper.native.updateData({
  224. paginationContent: swiper.native.paginationContent,
  225. })
  226. }
  227. if (params.type === 'custom' && params.renderCustom) {
  228. $el.html(params.renderCustom(swiper, current + 1, total));
  229. emit('paginationRender', $el[0]);
  230. } else {
  231. emit('paginationUpdate', $el[0]);
  232. }
  233. if (swiper.params.watchOverflow && swiper.enabled) {
  234. swiper.$wrapperEl[swiper.isLocked ? 'addPaginationClass' : 'removePaginationClass'](params.lockClass);
  235. }
  236. }
  237. function render() {
  238. // Render Container
  239. const params = swiper.params.pagination;
  240. if (isPaginationDisabled()) return;
  241. const slidesLength =
  242. swiper.virtual && swiper.params.virtual.enabled ?
  243. swiper.virtual.slides.length :
  244. swiper.slides.length;
  245. const $el = swiper.pagination.$el;
  246. let paginationHTML = 0;
  247. if (params.type === 'bullets') {
  248. let numberOfBullets = swiper.params.loop ?
  249. Math.ceil((slidesLength - swiper.loopedSlides * 2) / swiper.params.slidesPerGroup) :
  250. swiper.snapGrid.length;
  251. if (
  252. swiper.params.freeMode &&
  253. swiper.params.freeMode.enabled &&
  254. !swiper.params.loop &&
  255. numberOfBullets > slidesLength
  256. ) {
  257. numberOfBullets = slidesLength;
  258. }
  259. for (let i = 0; i < numberOfBullets; i += 1) {
  260. if (params.renderBullet) {
  261. paginationHTML += params.renderBullet.call(swiper, i, params.bulletClass);
  262. }
  263. // else {
  264. // paginationHTML +=
  265. // `<${params.bulletElement} class="${params.bulletClass}"></${params.bulletElement}>`;
  266. // }
  267. // paginationHTML += 1;
  268. else {
  269. swiper.native.paginationType = "bullets";
  270. swiper.native.paginationContent.push({
  271. index: i,
  272. outerWidth: 16,
  273. outerHeight: 16,
  274. classContent: [params.bulletClass],
  275. styleContent: {},
  276. addPaginationItemClass: function(value) {
  277. this.classContent = Array.from(new Set([...this.classContent,
  278. ...value.split(" ")
  279. ]));
  280. },
  281. removePaginationItemClass: function(value) {
  282. this.classContent = this.classContent.filter(item => !value.split(
  283. " ").includes(item));
  284. },
  285. setCss: function(value) {
  286. // vueNative['itemStyle'] = {
  287. // ...vueNative['itemStyle'],
  288. // ...value
  289. // };Object.keys(value).forEach((item) => {
  290. Object.keys(value).forEach((item) => {
  291. // this.$set(this.itemStyle, item, value[item])
  292. this.styleContent[item] = value[item];
  293. })
  294. // this.$set(this.itemStyle, item, value[item])
  295. }
  296. });
  297. swiper.native.updateData({
  298. paginationType: swiper.native.paginationType,
  299. paginationContent: swiper.native.paginationContent,
  300. })
  301. }
  302. }
  303. // $el.html(paginationHTML);
  304. // swiper.$wrapperEl.addPaginationItemClass(params.bulletClass)
  305. // swiper.pagination.bullets = $el.find(classesToSelector(params.bulletClass));
  306. swiper.pagination.bullets = swiper.native.paginationContent;
  307. }
  308. if (params.type === 'fraction') {
  309. if (params.renderFraction) {
  310. paginationHTML = params.renderFraction.call(swiper, params.currentClass, params.totalClass);
  311. } else {
  312. swiper.native.paginationType = "fraction";
  313. // paginationHTML =
  314. // `<span class="${params.currentClass}"></span>` +
  315. // ' / ' +
  316. // `<span class="${params.totalClass}"></span>`;
  317. swiper.native.paginationContent = {
  318. currentClass: params.currentClass,
  319. totalClass: params.totalClass
  320. }
  321. swiper.native.updateData({
  322. paginationType: swiper.native.paginationType,
  323. paginationContent: swiper.native.paginationContent,
  324. })
  325. }
  326. }
  327. if (params.type === 'progressbar') {
  328. if (params.renderProgressbar) {
  329. paginationHTML = params.renderProgressbar.call(swiper, params.progressbarFillClass);
  330. } else {
  331. swiper.native.paginationType = "progressbar";
  332. // paginationHTML = `<span class="${params.progressbarFillClass}"></span>`;
  333. swiper.native.paginationContent = {
  334. progressbarFillClass: params.progressbarFillClass,
  335. styleContent: {
  336. transform: '',
  337. transitionDuration: ''
  338. },
  339. transition: function(value) {
  340. this.styleContent.transitionDuration = `${value}ms`;
  341. },
  342. transform: function(value) {
  343. this.styleContent.transform = value;
  344. },
  345. }
  346. swiper.native.updateData({
  347. paginationType: swiper.native.paginationType,
  348. paginationContent: swiper.native.paginationContent,
  349. })
  350. }
  351. // $el.html(paginationHTML);
  352. }
  353. if (params.type !== 'custom') {
  354. emit('paginationRender', swiper.pagination.$el[0]);
  355. }
  356. }
  357. function init() {
  358. const params = swiper.params.pagination;
  359. if (!params.el) return;
  360. // swiper.native.showIndicators = true;
  361. swiper.native.updateData({
  362. showIndicators: true
  363. })
  364. let $el = params.el;
  365. if (params.type === 'bullets' && params.clickable) {
  366. swiper.$wrapperEl.addPaginationClass(params.clickableClass);
  367. }
  368. swiper.$wrapperEl.addPaginationClass(params.modifierClass + params.type);
  369. swiper.$wrapperEl.addPaginationClass(params.modifierClass + swiper.params.direction);
  370. if (params.type === 'bullets' && params.dynamicBullets) {
  371. swiper.$wrapperEl.addPaginationClass(`${params.modifierClass}${params.type}-dynamic`);
  372. dynamicBulletIndex = 0;
  373. if (params.dynamicMainBullets < 1) {
  374. params.dynamicMainBullets = 1;
  375. }
  376. }
  377. if (params.type === 'progressbar' && params.progressbarOpposite) {
  378. swiper.$wrapperEl.addPaginationClass(params.progressbarOppositeClass);
  379. }
  380. if (params.clickable) {
  381. swiper.on('paginationItemClick', function onClick(_s, itemIndex) {
  382. let index = itemIndex * swiper.params.slidesPerGroup;
  383. if (swiper.params.loop) index += swiper.loopedSlides;
  384. swiper.slideTo(index);
  385. });
  386. }
  387. Object.assign(swiper.pagination, {
  388. $el,
  389. el: $el,
  390. });
  391. if (!swiper.enabled) {
  392. swiper.$wrapperEl.addPaginationClass(params.lockClass);
  393. }
  394. }
  395. function destroy() {
  396. const params = swiper.params.pagination;
  397. if (isPaginationDisabled()) return;
  398. const $el = swiper.pagination.$el;
  399. if (params.clickable) {
  400. swiper.off('paginationItemClick', classesToSelector(params.bulletClass));
  401. }
  402. }
  403. on('init update', () => {
  404. if (swiper.native.paginationContent) {
  405. swiper.native.updateData({
  406. paginationContent: []
  407. })
  408. }
  409. // swiper.native.paginationContent = [];
  410. init();
  411. render();
  412. update();
  413. });
  414. on('activeIndexChange', () => {
  415. if (swiper.params.loop) {
  416. update();
  417. } else if (typeof swiper.snapIndex === 'undefined') {
  418. update();
  419. }
  420. });
  421. on('snapIndexChange', () => {
  422. if (!swiper.params.loop) {
  423. update();
  424. }
  425. });
  426. on('slidesLengthChange', () => {
  427. if (swiper.params.loop) {
  428. render();
  429. update();
  430. }
  431. });
  432. on('snapGridLengthChange', () => {
  433. if (!swiper.params.loop) {
  434. render();
  435. update();
  436. }
  437. });
  438. on('destroy', () => {
  439. destroy();
  440. });
  441. on('enable disable', () => {
  442. const {
  443. $el
  444. } = swiper.pagination;
  445. if ($el) {
  446. swiper.$wrapperEl[swiper.enabled ? 'removePaginationClass' : 'addPaginationClass'](swiper.params
  447. .pagination.lockClass);
  448. }
  449. });
  450. on('lock unlock', () => {
  451. update();
  452. });
  453. on('click', (_s, e) => {
  454. const targetEl = e.target;
  455. const {
  456. $el
  457. } = swiper.pagination;
  458. if (
  459. swiper.params.pagination.el &&
  460. swiper.params.pagination.hideOnClick &&
  461. $el.length > 0 &&
  462. !$(targetEl).hasClass(swiper.params.pagination.bulletClass)
  463. ) {
  464. if (
  465. swiper.navigation &&
  466. ((swiper.navigation.nextEl && targetEl === swiper.navigation.nextEl) ||
  467. (swiper.navigation.prevEl && targetEl === swiper.navigation.prevEl))
  468. )
  469. return;
  470. const isHidden = $el.hasClass(swiper.params.pagination.hiddenClass);
  471. if (isHidden === true) {
  472. emit('paginationShow');
  473. } else {
  474. emit('paginationHide');
  475. }
  476. $el.toggleClass(swiper.params.pagination.hiddenClass);
  477. }
  478. });
  479. Object.assign(swiper.pagination, {
  480. render,
  481. update,
  482. init,
  483. destroy,
  484. });
  485. }