export default function Virtual({ swiper, extendParams, on }) { extendParams({ virtual: { enabled: false, slides: [], cache: true, renderSlide: null, renderExternal: null, renderExternalUpdate: true, addSlidesBefore: 0, addSlidesAfter: 0, }, }); let cssModeTimeout; swiper.virtual = { cache: {}, from: undefined, to: undefined, slides: [], offset: 0, slidesGrid: [], }; function renderSlide(slide, index) { const params = swiper.params.virtual; if (params.cache && swiper.virtual.cache[index]) { return swiper.virtual.cache[index]; } // const $slideEl = params.renderSlide ? // $(params.renderSlide.call(swiper, slide, index)) : // $( // `
${slide}
`, // ); // if (!$slideEl.attr('data-swiper-slide-index')) $slideEl.attr('data-swiper-slide-index', index); // if (params.cache) swiper.virtual.cache[index] = $slideEl; // return $slideEl; } function onRendered() { swiper.updateSlides(); swiper.updateProgress(); swiper.updateSlidesClasses(); if (swiper.lazy && swiper.params.lazy.enabled) { swiper.lazy.load(); } } async function update(force) { const { slidesPerView, slidesPerGroup, centeredSlides } = swiper.params; const { addSlidesBefore, addSlidesAfter } = swiper.params.virtual; const { from: previousFrom, to: previousTo, slides, slidesGrid: previousSlidesGrid, offset: previousOffset, } = swiper.virtual; if (!swiper.params.cssMode) { swiper.updateActiveIndex(); } const activeIndex = swiper.activeIndex || 0; let offsetProp; if (swiper.rtlTranslate) offsetProp = 'right'; else offsetProp = swiper.isHorizontal() ? 'left' : 'top'; let slidesAfter; let slidesBefore; if (centeredSlides) { slidesAfter = Math.floor(slidesPerView / 2) + slidesPerGroup + addSlidesAfter; slidesBefore = Math.floor(slidesPerView / 2) + slidesPerGroup + addSlidesBefore; } else { slidesAfter = slidesPerView + (slidesPerGroup - 1) + addSlidesAfter; slidesBefore = slidesPerGroup + addSlidesBefore; } const from = Math.max((activeIndex || 0) - slidesBefore, 0); const to = Math.min((activeIndex || 0) + slidesAfter, slides.length - 1); const offset = (swiper.slidesGrid[from] || 0) - (swiper.slidesGrid[0] || 0); Object.assign(swiper.virtual, { from, to, offset, slidesGrid: swiper.slidesGrid, }); function onRendered() { swiper.updateSlides(); swiper.updateProgress(); swiper.updateSlidesClasses(); if (swiper.lazy && swiper.params.lazy.enabled) { swiper.lazy.load(); } } if (previousFrom === from && previousTo === to && !force) { if (swiper.slidesGrid !== previousSlidesGrid && offset !== previousOffset) { swiper.slides.css(offsetProp, `${offset}px`); } swiper.updateProgress(); return; } if (swiper.params.virtual.renderExternal) { swiper.params.virtual.renderExternal.call(swiper, { offset, from, to, slides: (function getSlides() { const slidesToRender = []; if (swiper.params.virtual.type == 'keep') { for (let i = 0; i < from; i += 1) { slidesToRender.push(""); } } for (let i = from; i <= to; i += 1) { slidesToRender.push(slides[i]); } return slidesToRender; })(), }); if (swiper.params.virtual.renderExternalUpdate) { onRendered(); } return; } const prependIndexes = []; const appendIndexes = []; if (force) { swiper.$wrapperEl.find(`.${swiper.params.slideClass}`).remove(); } else { for (let i = previousFrom; i <= previousTo; i += 1) { if (i < from || i > to) { swiper.virtualList.splice(swiper.virtualList.findIndex((item) => { return item == slides[i] }), 1) swiper.virtualIndexList.splice(swiper.virtualIndexList.findIndex((item) => { return item == i }), 1) // swiper.slides[i].virtualShow = false; } } } for (let i = 0; i < slides.length; i += 1) { if (i >= from && i <= to) { if (typeof previousTo === 'undefined' || force) { appendIndexes.push(i); } else { if (i > previousTo) appendIndexes.push(i); if (i < previousFrom) prependIndexes.push(i); } } } // let list = []; appendIndexes.forEach((index) => { // if (swiper.slides[index]) { // swiper.slides[index].virtualShow = true; // } else { swiper.virtualList.push(slides[index]); swiper.virtualIndexList.push(index) // } // renderSlide(slides[index], index) // renderSlide(slides[index], index) // swiper.$wrapperEl.append(renderSlide(slides[index], index)); }); prependIndexes .sort((a, b) => b - a) .forEach((index) => { // swiper.slides[index].virtualShow = true; swiper.virtualList.unshift(slides[index]); swiper.virtualIndexList.unshift(index) // swiper.$wrapperEl.prepend(renderSlide(slides[index], index)); }); swiper.native.emit("input", [swiper.virtualList]) onRendered(); } function appendSlide(slides) { if (typeof slides === 'object' && 'length' in slides) { for (let i = 0; i < slides.length; i += 1) { if (slides[i]) swiper.virtual.slides.push(slides[i]); } } else { swiper.virtual.slides.push(slides); } update(true); } function prependSlide(slides) { const activeIndex = swiper.activeIndex; let newActiveIndex = activeIndex + 1; let numberOfNewSlides = 1; if (Array.isArray(slides)) { for (let i = 0; i < slides.length; i += 1) { if (slides[i]) swiper.virtual.slides.unshift(slides[i]); } newActiveIndex = activeIndex + slides.length; numberOfNewSlides = slides.length; } else { swiper.virtual.slides.unshift(slides); } if (swiper.params.virtual.cache) { const cache = swiper.virtual.cache; const newCache = {}; Object.keys(cache).forEach((cachedIndex) => { const $cachedEl = cache[cachedIndex]; const cachedElIndex = $cachedEl.attr('data-swiper-slide-index'); if (cachedElIndex) { $cachedEl.attr( 'data-swiper-slide-index', parseInt(cachedElIndex, 10) + numberOfNewSlides, ); } newCache[parseInt(cachedIndex, 10) + numberOfNewSlides] = $cachedEl; }); swiper.virtual.cache = newCache; } update(true); swiper.slideTo(newActiveIndex, 0); } function removeSlide(slidesIndexes) { if (typeof slidesIndexes === 'undefined' || slidesIndexes === null) return; let activeIndex = swiper.activeIndex; if (Array.isArray(slidesIndexes)) { for (let i = slidesIndexes.length - 1; i >= 0; i -= 1) { swiper.virtual.slides.splice(slidesIndexes[i], 1); if (swiper.params.virtual.cache) { delete swiper.virtual.cache[slidesIndexes[i]]; } if (slidesIndexes[i] < activeIndex) activeIndex -= 1; activeIndex = Math.max(activeIndex, 0); } } else { swiper.virtual.slides.splice(slidesIndexes, 1); if (swiper.params.virtual.cache) { delete swiper.virtual.cache[slidesIndexes]; } if (slidesIndexes < activeIndex) activeIndex -= 1; activeIndex = Math.max(activeIndex, 0); } update(true); swiper.slideTo(activeIndex, 0); } function removeAllSlides() { swiper.virtual.slides = []; if (swiper.params.virtual.cache) { swiper.virtual.cache = {}; } update(true); swiper.slideTo(0, 0); } on('beforeInit', () => { if (!swiper.params.virtual.enabled) return; swiper.virtual.slides = swiper.params.virtual.slides; swiper.classNames.push(`${swiper.params.containerModifierClass}virtual`); swiper.params.watchSlidesProgress = true; swiper.originalParams.watchSlidesProgress = true; if (!swiper.params.initialSlide) { update(); } }); // on('beforeUpdate', () => { // if (!swiper.params.virtual.enabled) return; // let offsetProp; // if (swiper.rtlTranslate) offsetProp = 'right'; // else offsetProp = swiper.isHorizontal() ? 'left' : 'top'; // swiper.slides.forEach((item, index) => { // item.dataSwiperSlideIndex = swiper.virtualIndexList[index]; // item.css({ // [offsetProp]: `${swiper.virtual.offset}px` // }) // }) // }) on('setTranslate', async () => { if (!swiper.params.virtual.enabled) return; if (swiper.params.cssMode && !swiper._immediateVirtual) { clearTimeout(cssModeTimeout); cssModeTimeout = setTimeout(() => { update(); }, 100); } else { console.log("update==========") clearTimeout(cssModeTimeout); cssModeTimeout = setTimeout(() => { update(); }, 100); // update(); } }); Object.assign(swiper.virtual, { appendSlide, prependSlide, removeSlide, removeAllSlides, update, }); }