UNPKG

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