virtual-image-layout
v1.0.6
Published
A virtual scrolling justified image gallery layout library, framework-agnostic
Maintainers
Readme
图片等高布局 - 虚拟列表
一个基于虚拟列表技术的高性能图片等高布局项目,支持大量图片的流畅展示。
功能特性
- 虚拟列表渲染:只渲染可视区域内的图片,大幅提升性能
- 等高布局算法:智能计算每行图片的宽度,保持行高一致
- 响应式设计:自动适配不同屏幕尺寸
- 懒加载:滚动加载更多图片
- 图片曝光统计:使用 IntersectionObserver API 监听图片曝光
- 错误处理:自动移除加载失败的图片
技术栈
- 原生 JavaScript:核心布局算法
- CSS3:样式和动画效果
- IntersectionObserver API:图片曝光监听
快速开始
npm i virtual-image-layout
<template>
<div class="virtual-layout-wrapper">
<div ref="containerRef" class="justified-gallery"></div>
<div v-if="loading" class="load-more-waterfall wave-loading">
<span style="--time:1"></span>
<span style="--time:2"></span>
<span style="--time:3"></span>
</div>
<div v-if="noMore" class="load-more-waterfall">
<p class="tips-text2">已经到底了噢~</p>
</div>
</div>
</template>import VirtualImageLayout from 'virtual-image-layout';
import 'virtual-image-layout/css/index.css';
export default {
name: 'ListDome',
data() {
return {
layout: null,
page: 1,
loading: false,
noMore: false,
hasMore: true,
};
},
mounted() {
this.layout = new VirtualImageLayout(this.$refs.containerRef, {
rowGap: 16,
onRenderItem: (item, imgWidth, imgHeight) => {
return `
<div class="images-gallery" data-index="${item.data_index}">
<a class="images" style="width:${imgWidth}px;height:${imgHeight}px;">
<img src="${item.img}" alt="${item.res_name || ''}">
</a>
<a class="name">${item.res_name || ''}</a>
</div>
`;
},
ExposureCallback: (burialPoint) => {
console.log('曝光数据:', burialPoint);
},
});
// 监听滚动加载更多
window.addEventListener('scroll', this.onScroll);
this.loadMore();
},
beforeUnmount() {
window.removeEventListener('scroll', this.onScroll);
this.layout = null;
},
methods: {
onScroll() {
const scrollTop = window.pageYOffset;
const totalHeight = document.documentElement.scrollHeight;
const viewHeight = window.innerHeight;
if (scrollTop + viewHeight + 500 > totalHeight && this.hasMore && !this.loading) {
this.loadMore();
}
},
async loadMore() {
this.loading = true;
// TODO: 替换成你的真实接口
const list = await this.fetchData(this.page);
this.loading = false;
if (list.length === 0) {
this.hasMore = false;
this.noMore = true;
if (this.layout) this.layout.hasMore = false;
return;
}
this.layout && this.layout.addImages(list);
this.page++;
},
fetchData() {
// 模拟接口,替换成真实请求
return Promise.resolve([
{
"res_name": "现代别墅外观3D模型",
"img": "https://placehold.co/400x300/png",
"width": 400,
"height": 300
},
]);
},
},
};使用说明
// 初始化虚拟列表
var layout = new VirtualImageLayout('container', {
rowGap: 16, // 行间距
titleGap: 30, // 标题高度(可选)
// 自定义渲染函数
onRenderItem: (item, imgWidth, imgHeight, rowHeight) => {
return `
<div class="images-gallery">
<a class="images" style="width: ${imgWidth}px; height: ${imgHeight}px;">
<img src="${item.img}" alt="${item.res_name}">
</a>
<a class="name">${item.res_name}</a>
</div>
`;
},
// 曝光回调(可选)
ExposureCallback(burialPoint) {
console.log('曝光数据:', burialPoint);
}
});
// 添加图片数据
layout.addImages(imageData);核心类说明
VirtualImageLayout
虚拟列表核心类,负责图片布局和渲染。
构造函数参数
| 参数 | 类型 | 说明 | |------|------|------| | containerId | String | 容器元素 ID | | options | Object | 配置选项 |
配置选项
| 选项 | 类型 | 默认值 | 说明 | |------|------|--------|------| | rowGap | Number | 16 | 行间距(像素) | | titleGap | Number | - | 标题高度(像素),设置后显示标题 | | onRenderItem | Function | - | 自定义渲染函数 | | ExposureCallback | Function | - | 图片曝光回调函数 |
主要方法
addImages(images): 添加图片数据updateVirtualRows(): 更新可视区域的行handleResize(): 处理窗口大小变化
性能优化
- 虚拟滚动:只渲染可视区域 + 缓冲区的图片
- 防抖处理:滚动和窗口大小变化事件使用防抖
- 图片懒加载:滚动到底部自动加载更多
- 智能布局算法:动态计算目标行高,适配不同屏幕
浏览器兼容性
- Chrome (推荐)
- Firefox
- Safari
- Edge
注意事项
- 图片数据必须包含
width和height字段 - 建议图片宽度大于高度,以获得更好的布局效果
- 图片链接必须是公开可访问的 URL
License
MIT
贡献
欢迎提交 Issue 和 Pull Request!
