UNPKG

7.74 kBJavaScriptView Raw
1import $ from '../../shared/dom.js';
2import { setCSSProperty } from '../../shared/utils.js';
3export default function Virtual({
4 swiper,
5 extendParams,
6 on
7}) {
8 extendParams({
9 virtual: {
10 enabled: false,
11 slides: [],
12 cache: true,
13 renderSlide: null,
14 renderExternal: null,
15 renderExternalUpdate: true,
16 addSlidesBefore: 0,
17 addSlidesAfter: 0
18 }
19 });
20 swiper.virtual = {
21 cache: {},
22 from: undefined,
23 to: undefined,
24 slides: [],
25 offset: 0,
26 slidesGrid: []
27 };
28
29 function renderSlide(slide, index) {
30 const params = swiper.params.virtual;
31
32 if (params.cache && swiper.virtual.cache[index]) {
33 return swiper.virtual.cache[index];
34 }
35
36 const $slideEl = params.renderSlide ? $(params.renderSlide.call(swiper, slide, index)) : $(`<div class="${swiper.params.slideClass}" data-swiper-slide-index="${index}">${slide}</div>`);
37 if (!$slideEl.attr('data-swiper-slide-index')) $slideEl.attr('data-swiper-slide-index', index);
38 if (params.cache) swiper.virtual.cache[index] = $slideEl;
39 return $slideEl;
40 }
41
42 function update(force) {
43 const {
44 slidesPerView,
45 slidesPerGroup,
46 centeredSlides
47 } = swiper.params;
48 const {
49 addSlidesBefore,
50 addSlidesAfter
51 } = swiper.params.virtual;
52 const {
53 from: previousFrom,
54 to: previousTo,
55 slides,
56 slidesGrid: previousSlidesGrid,
57 offset: previousOffset
58 } = swiper.virtual;
59 swiper.updateActiveIndex();
60 const activeIndex = swiper.activeIndex || 0;
61 let offsetProp;
62 if (swiper.rtlTranslate) offsetProp = 'right';else offsetProp = swiper.isHorizontal() ? 'left' : 'top';
63 let slidesAfter;
64 let slidesBefore;
65
66 if (centeredSlides) {
67 slidesAfter = Math.floor(slidesPerView / 2) + slidesPerGroup + addSlidesAfter;
68 slidesBefore = Math.floor(slidesPerView / 2) + slidesPerGroup + addSlidesBefore;
69 } else {
70 slidesAfter = slidesPerView + (slidesPerGroup - 1) + addSlidesAfter;
71 slidesBefore = slidesPerGroup + addSlidesBefore;
72 }
73
74 const from = Math.max((activeIndex || 0) - slidesBefore, 0);
75 const to = Math.min((activeIndex || 0) + slidesAfter, slides.length - 1);
76 const offset = (swiper.slidesGrid[from] || 0) - (swiper.slidesGrid[0] || 0);
77 Object.assign(swiper.virtual, {
78 from,
79 to,
80 offset,
81 slidesGrid: swiper.slidesGrid
82 });
83
84 function onRendered() {
85 swiper.updateSlides();
86 swiper.updateProgress();
87 swiper.updateSlidesClasses();
88
89 if (swiper.lazy && swiper.params.lazy.enabled) {
90 swiper.lazy.load();
91 }
92 }
93
94 if (previousFrom === from && previousTo === to && !force) {
95 if (swiper.slidesGrid !== previousSlidesGrid && offset !== previousOffset) {
96 swiper.slides.css(offsetProp, `${offset}px`);
97 }
98
99 swiper.updateProgress();
100 return;
101 }
102
103 if (swiper.params.virtual.renderExternal) {
104 swiper.params.virtual.renderExternal.call(swiper, {
105 offset,
106 from,
107 to,
108 slides: function getSlides() {
109 const slidesToRender = [];
110
111 for (let i = from; i <= to; i += 1) {
112 slidesToRender.push(slides[i]);
113 }
114
115 return slidesToRender;
116 }()
117 });
118
119 if (swiper.params.virtual.renderExternalUpdate) {
120 onRendered();
121 }
122
123 return;
124 }
125
126 const prependIndexes = [];
127 const appendIndexes = [];
128
129 if (force) {
130 swiper.$wrapperEl.find(`.${swiper.params.slideClass}`).remove();
131 } else {
132 for (let i = previousFrom; i <= previousTo; i += 1) {
133 if (i < from || i > to) {
134 swiper.$wrapperEl.find(`.${swiper.params.slideClass}[data-swiper-slide-index="${i}"]`).remove();
135 }
136 }
137 }
138
139 for (let i = 0; i < slides.length; i += 1) {
140 if (i >= from && i <= to) {
141 if (typeof previousTo === 'undefined' || force) {
142 appendIndexes.push(i);
143 } else {
144 if (i > previousTo) appendIndexes.push(i);
145 if (i < previousFrom) prependIndexes.push(i);
146 }
147 }
148 }
149
150 appendIndexes.forEach(index => {
151 swiper.$wrapperEl.append(renderSlide(slides[index], index));
152 });
153 prependIndexes.sort((a, b) => b - a).forEach(index => {
154 swiper.$wrapperEl.prepend(renderSlide(slides[index], index));
155 });
156 swiper.$wrapperEl.children('.swiper-slide').css(offsetProp, `${offset}px`);
157 onRendered();
158 }
159
160 function appendSlide(slides) {
161 if (typeof slides === 'object' && 'length' in slides) {
162 for (let i = 0; i < slides.length; i += 1) {
163 if (slides[i]) swiper.virtual.slides.push(slides[i]);
164 }
165 } else {
166 swiper.virtual.slides.push(slides);
167 }
168
169 update(true);
170 }
171
172 function prependSlide(slides) {
173 const activeIndex = swiper.activeIndex;
174 let newActiveIndex = activeIndex + 1;
175 let numberOfNewSlides = 1;
176
177 if (Array.isArray(slides)) {
178 for (let i = 0; i < slides.length; i += 1) {
179 if (slides[i]) swiper.virtual.slides.unshift(slides[i]);
180 }
181
182 newActiveIndex = activeIndex + slides.length;
183 numberOfNewSlides = slides.length;
184 } else {
185 swiper.virtual.slides.unshift(slides);
186 }
187
188 if (swiper.params.virtual.cache) {
189 const cache = swiper.virtual.cache;
190 const newCache = {};
191 Object.keys(cache).forEach(cachedIndex => {
192 const $cachedEl = cache[cachedIndex];
193 const cachedElIndex = $cachedEl.attr('data-swiper-slide-index');
194
195 if (cachedElIndex) {
196 $cachedEl.attr('data-swiper-slide-index', parseInt(cachedElIndex, 10) + 1);
197 }
198
199 newCache[parseInt(cachedIndex, 10) + numberOfNewSlides] = $cachedEl;
200 });
201 swiper.virtual.cache = newCache;
202 }
203
204 update(true);
205 swiper.slideTo(newActiveIndex, 0);
206 }
207
208 function removeSlide(slidesIndexes) {
209 if (typeof slidesIndexes === 'undefined' || slidesIndexes === null) return;
210 let activeIndex = swiper.activeIndex;
211
212 if (Array.isArray(slidesIndexes)) {
213 for (let i = slidesIndexes.length - 1; i >= 0; i -= 1) {
214 swiper.virtual.slides.splice(slidesIndexes[i], 1);
215
216 if (swiper.params.virtual.cache) {
217 delete swiper.virtual.cache[slidesIndexes[i]];
218 }
219
220 if (slidesIndexes[i] < activeIndex) activeIndex -= 1;
221 activeIndex = Math.max(activeIndex, 0);
222 }
223 } else {
224 swiper.virtual.slides.splice(slidesIndexes, 1);
225
226 if (swiper.params.virtual.cache) {
227 delete swiper.virtual.cache[slidesIndexes];
228 }
229
230 if (slidesIndexes < activeIndex) activeIndex -= 1;
231 activeIndex = Math.max(activeIndex, 0);
232 }
233
234 update(true);
235 swiper.slideTo(activeIndex, 0);
236 }
237
238 function removeAllSlides() {
239 swiper.virtual.slides = [];
240
241 if (swiper.params.virtual.cache) {
242 swiper.virtual.cache = {};
243 }
244
245 update(true);
246 swiper.slideTo(0, 0);
247 }
248
249 on('beforeInit', () => {
250 if (!swiper.params.virtual.enabled) return;
251 swiper.virtual.slides = swiper.params.virtual.slides;
252 swiper.classNames.push(`${swiper.params.containerModifierClass}virtual`);
253 swiper.params.watchSlidesProgress = true;
254 swiper.originalParams.watchSlidesProgress = true;
255
256 if (!swiper.params.initialSlide) {
257 update();
258 }
259 });
260 on('setTranslate', () => {
261 if (!swiper.params.virtual.enabled) return;
262 update();
263 });
264 on('init update resize', () => {
265 if (!swiper.params.virtual.enabled) return;
266
267 if (swiper.params.cssMode) {
268 setCSSProperty(swiper.wrapperEl, '--swiper-virtual-size', `${swiper.virtualSize}px`);
269 }
270 });
271 Object.assign(swiper.virtual, {
272 appendSlide,
273 prependSlide,
274 removeSlide,
275 removeAllSlides,
276 update
277 });
278}
\No newline at end of file