When building image galleries in Uni-App mini-programs, rendering all swiper-item elements simultaneously can severely degrade performance. Loading dozens of high-resolution assets during initial navigation drains network bandwidth, spikes memory usage, and introduces noticeable frame drops or white-screen delays. A more efficient approach restricts DOM rendering to only the currently active slide alongside its immediate neighbors. This technique leverages conditional rendering directives combined with dynamic index tracking to maintain a fixed-size rendering window.
The implementation revolevs around maintaining a collection of indices marked for actual DOM creation. Upon navigating to a specific asset, the system initializes the render pool with the target index and its adjacent positions. Subsequent sliding events expand this pool outward while respecting circular pagination boundaries and eliminating redundant entries.
<swiper
:circular="true"
:current-index="activeAssetIndex"
@change="handleSlideTransition"
class="gallery-swiper"
>
<swiper-item v-for="(asset, idx) in imageGallery" :key="asset.id">
<image
v-if="renderPool.has(idx)"
:src="resolveSrc(asset.thumbPath)"
mode="aspect-fill"
/>
</swiper-item>
</swiper>
const imageGallery = ref([])
const activeAssetIndex = ref(0)
const renderPool = ref(new Set())
let pendingTargetId = null
const prepareGalleryData = (storagePayload) => storagePayload.map(entry => ({
id: entry._id,
thumbPath: entry.smallPicurl,
resolveSrc: (path) => path.replace('_small.webp', '.jpg')
}))
const initGallery = () => {
const cachedData = uni.getStorageSync('cachedImageList') || []
imageGallery.value = prepareGalleryData(cachedData)
}
const updateRenderWindow = () => {
const totalSlides = imageGallery.value.length
if (!totalSlides) return
const prev = activeAssetIndex.value === 0 ? totalSlides - 1 : activeAssetIndex.value - 1
const curr = activeAssetIndex.value
const next = activeAssetIndex.value === totalSlides - 1 ? 0 : activeAssetIndex.value + 1
renderPool.value.add(prev)
renderPool.value.add(curr)
renderPool.value.add(next)
}
onLoad((query) => {
pendingTargetId = query.targetId
initGallery()
const startIdx = imageGallery.value.findIndex(img => img.id === pendingTargetId)
if (startIdx > -1) {
activeAssetIndex.value = startIdx
updateRenderWindow()
}
})
const handleSlideTransition = (e) => {
activeAssetIndex.value = e.detail.current
updateRenderWindow()
}
Critical Implementation Details
- Utilizing a
Setfor the render window reduces lookup complexity to O(1) and automatically filters duplicate indices generated during rapid directional changes. - Boundary calculations employ direct arithmetic wrapping to safely handle edge cases without triggering invalid state updates.
- Memory consumption remains constant regardless of total asset count, as only three DOM nodes exist at any given time.
- Network payloads are strictly deferred until an index crosses into the active window threshold, preventing initial load bottlanecks.