keno-lee / vue-virt-list

⚡️ 一个支持vue2&vue3的高性能虚拟(滚动)列表组件 👉🏻 轻量3KB 百万数据渲染 满帧率滚动 丰富场景支持 📑 [vue虚拟列表] [vue虚拟滚动列表] [vue-virtual-list] [vue-virtual-scroll-list] [vue-virtual-scroller]

Home Page:https://keno-lee.github.io/vue-virt-list/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

设置buffer并不起作用

JQHee opened this issue · comments

image image

要设置一个限定的高度。可以设置给virt list的父容器,也可以直接设置给virt list

image image

要设置一个限定的高度。可以设置给virt list的父容器,也可以直接设置给virt list

是否解决你的问题?

scrollIntoView滚动到指定位置有时候不太对

<template>
	<view class="content">
		<view class="buttons-wrapper">
			<view class="to-bottom" @click="toBottomClick">底部</view>
			<view class="to-position" @click="toPositionClick">定位</view>
		</view>
		<view class="virtList-content">
			<VirtList
				class="virtList"
				ref="virtListRef"
				:buffer="2"
				itemKey="id"
				:list="items"
				:minSize="20"
				@toTop="onToTop"
				@toBottom="onToBottom"
				@itemResize="onItemResize"
				@scroll="onScroll"
			>
				<template #default="{ itemData, index }">
					<view class="virt-item" :data-index="index">
						<view v-if="itemData.type === 0">{{ index }} - {{ itemData.text }}</view>
						<image v-if="itemData.type === 1" :src="itemData.text" />
					</view>
				</template>
				<template #header v-if="isShowLoading">
					<view style="width: 100%; height: 20px; display: flex; justify-content: center; align-items: center; background-color: chocolate">loading...</view>
				</template>
			</VirtList>
		</view>
	</view>
</template>

<script>
import { VirtList } from 'vue-virt-list';
// 这个稍
export default {
	components: { VirtList },
	data() {
		return {
			items: [],
			isShowLoading: false,
			lastIndex: null
		};
	},
	onLoad() {
		this.virtListRef = this.$refs.virtListRef;
		for (let i = 0; i < 1000; i++) {
			const item = { text: '', id: i, type: 0 };
			item.text = '测试内容';
			if (i % 2 === 0) {
				item.text = '测试内容测试内容测试内容测试内容测试内容测试内容测试内容测试内容测试内容测试内容测试内容测试内容测试内容测试内容测试内容测试内容';
			} else if (i % 5 === 0) {
				item.type = 1;
				item.text = 'https://newfile.ofweek.net/fileremote/msg/chat/2023-04/20230419175448321_dl.png';
			}
			this.items.push(item);
		}
		this.$nextTick(() => {
			this.$refs.virtListRef.scrollToBottom();
		});
	},
	methods: {
		async onToTop() {
			console.log('onToTop');
			if (this.isShowLoading) return;
			this.isShowLoading = true;
		},
		async onToBottom() {
			console.log('onToBottom');
		},
		async onItemResize() {},
		async onScroll(event) {
			//console.log(event);
			const chatListWrapperDom = document.querySelector('.virtList-content');
			const offsetY = this.$refs.virtListRef && this.$refs.virtListRef.getOffset();
			const targetOffsetY = Math.abs(offsetY) + chatListWrapperDom.clientHeight;

			console.log(targetOffsetY);
			let list = document.querySelectorAll('.virt-item'); // 查找所有view元素
			for (let i = 0; i < list.length; i++) {
				const item = list[i];
				//debugger;
				if (targetOffsetY >= item.offsetTop && targetOffsetY <= item.offsetTop + item.clientHeight) {
					// 取出id
					if (this.lastIndex === item.dataset.index) {
						return;
					}
					this.lastIndex = item.dataset.index;
					console.log('目标元素 item.dataset.index', item.dataset.index);
					console.log('目标元素 item.dataset.offsetTop', item.offsetTop);
					console.log('目标元素 item.dataset.maxOffsetY', item.offsetTop + item.clientHeight);
					break;
				}
			}
		},
		toBottomClick() {
			this.$refs.virtListRef?.scrollToBottom();
		},
		toPositionClick() {
			let timeout = setTimeout(() => {
				this.$refs.virtListRef?.scrollIntoView(50);
				clearTimeout(timeout);
				timeout = null;
			}, 20);
		}
	}
};
</script>

<style lang="scss" scoped>
.content {
	width: 100%;
	height: 100%;
	display: flex;
	flex-direction: column;
	.buttons-wrapper {
		display: flex;
		flex-direction: row;
		height: 8vmin;
	}
	.virtList-content {
		width: 100%;
		height: calc(100vmin - 11.73vmin - 8vmin);
	}
}
</style>

首次滚动到底部后,再定位到指定50位置时,不正确
image

buffer 设置了数量,也不是固定的

滑动到底部也没有日志打印

buffer 设置了数量,也不是固定的

buffer的确不是固定数量,当没有必要的时候,会不渲染buffer

滑动到底部也没有日志打印

我在chrome中手机模式中测试是有的。是否跟uniapp有关?

首次滚动到底部后,再定位到指定50位置时,不正确 image

确实存在问题。修复中,今天会发版

v1.0.5已解决该问题。pr内容:#8

scrollIntoView滚动到指定位置有时候不太对

<template>
	<view class="content">
		<view class="buttons-wrapper">
			<view class="to-bottom" @click="toBottomClick">底部</view>
			<view class="to-position" @click="toPositionClick">定位</view>
		</view>
		<view class="virtList-content">
			<VirtList
				class="virtList"
				ref="virtListRef"
				:buffer="2"
				itemKey="id"
				:list="items"
				:minSize="20"
				@toTop="onToTop"
				@toBottom="onToBottom"
				@itemResize="onItemResize"
				@scroll="onScroll"
			>
				<template #default="{ itemData, index }">
					<view class="virt-item" :data-index="index">
						<view v-if="itemData.type === 0">{{ index }} - {{ itemData.text }}</view>
						<image v-if="itemData.type === 1" :src="itemData.text" />
					</view>
				</template>
				<template #header v-if="isShowLoading">
					<view style="width: 100%; height: 20px; display: flex; justify-content: center; align-items: center; background-color: chocolate">loading...</view>
				</template>
			</VirtList>
		</view>
	</view>
</template>

<script>
import { VirtList } from 'vue-virt-list';
// 这个稍
export default {
	components: { VirtList },
	data() {
		return {
			items: [],
			isShowLoading: false,
			lastIndex: null
		};
	},
	onLoad() {
		this.virtListRef = this.$refs.virtListRef;
		for (let i = 0; i < 1000; i++) {
			const item = { text: '', id: i, type: 0 };
			item.text = '测试内容';
			if (i % 2 === 0) {
				item.text = '测试内容测试内容测试内容测试内容测试内容测试内容测试内容测试内容测试内容测试内容测试内容测试内容测试内容测试内容测试内容测试内容';
			} else if (i % 5 === 0) {
				item.type = 1;
				item.text = 'https://newfile.ofweek.net/fileremote/msg/chat/2023-04/20230419175448321_dl.png';
			}
			this.items.push(item);
		}
		this.$nextTick(() => {
			this.$refs.virtListRef.scrollToBottom();
		});
	},
	methods: {
		async onToTop() {
			console.log('onToTop');
			if (this.isShowLoading) return;
			this.isShowLoading = true;
		},
		async onToBottom() {
			console.log('onToBottom');
		},
		async onItemResize() {},
		async onScroll(event) {
			//console.log(event);
			const chatListWrapperDom = document.querySelector('.virtList-content');
			const offsetY = this.$refs.virtListRef && this.$refs.virtListRef.getOffset();
			const targetOffsetY = Math.abs(offsetY) + chatListWrapperDom.clientHeight;

			console.log(targetOffsetY);
			let list = document.querySelectorAll('.virt-item'); // 查找所有view元素
			for (let i = 0; i < list.length; i++) {
				const item = list[i];
				//debugger;
				if (targetOffsetY >= item.offsetTop && targetOffsetY <= item.offsetTop + item.clientHeight) {
					// 取出id
					if (this.lastIndex === item.dataset.index) {
						return;
					}
					this.lastIndex = item.dataset.index;
					console.log('目标元素 item.dataset.index', item.dataset.index);
					console.log('目标元素 item.dataset.offsetTop', item.offsetTop);
					console.log('目标元素 item.dataset.maxOffsetY', item.offsetTop + item.clientHeight);
					break;
				}
			}
		},
		toBottomClick() {
			this.$refs.virtListRef?.scrollToBottom();
		},
		toPositionClick() {
			let timeout = setTimeout(() => {
				this.$refs.virtListRef?.scrollIntoView(50);
				clearTimeout(timeout);
				timeout = null;
			}, 20);
		}
	}
};
</script>

<style lang="scss" scoped>
.content {
	width: 100%;
	height: 100%;
	display: flex;
	flex-direction: column;
	.buttons-wrapper {
		display: flex;
		flex-direction: row;
		height: 8vmin;
	}
	.virtList-content {
		width: 100%;
		height: calc(100vmin - 11.73vmin - 8vmin);
	}
}
</style>

代码中我看在滚动中在获取当前index,其实可以通过内部的reaciveData中的renderBeigin获取

调试窗口变大变小,滚动到顶部有时候有,有时候没有滚动到底部日志打印

default.mov

scrollIntoView滚动到指定位置有时候不太对

<template>
	<view class="content">
		<view class="buttons-wrapper">
			<view class="to-bottom" @click="toBottomClick">底部</view>
			<view class="to-position" @click="toPositionClick">定位</view>
		</view>
		<view class="virtList-content">
			<VirtList
				class="virtList"
				ref="virtListRef"
				:buffer="2"
				itemKey="id"
				:list="items"
				:minSize="20"
				@toTop="onToTop"
				@toBottom="onToBottom"
				@itemResize="onItemResize"
				@scroll="onScroll"
			>
				<template #default="{ itemData, index }">
					<view class="virt-item" :data-index="index">
						<view v-if="itemData.type === 0">{{ index }} - {{ itemData.text }}</view>
						<image v-if="itemData.type === 1" :src="itemData.text" />
					</view>
				</template>
				<template #header v-if="isShowLoading">
					<view style="width: 100%; height: 20px; display: flex; justify-content: center; align-items: center; background-color: chocolate">loading...</view>
				</template>
			</VirtList>
		</view>
	</view>
</template>

<script>
import { VirtList } from 'vue-virt-list';
// 这个稍
export default {
	components: { VirtList },
	data() {
		return {
			items: [],
			isShowLoading: false,
			lastIndex: null
		};
	},
	onLoad() {
		this.virtListRef = this.$refs.virtListRef;
		for (let i = 0; i < 1000; i++) {
			const item = { text: '', id: i, type: 0 };
			item.text = '测试内容';
			if (i % 2 === 0) {
				item.text = '测试内容测试内容测试内容测试内容测试内容测试内容测试内容测试内容测试内容测试内容测试内容测试内容测试内容测试内容测试内容测试内容';
			} else if (i % 5 === 0) {
				item.type = 1;
				item.text = 'https://newfile.ofweek.net/fileremote/msg/chat/2023-04/20230419175448321_dl.png';
			}
			this.items.push(item);
		}
		this.$nextTick(() => {
			this.$refs.virtListRef.scrollToBottom();
		});
	},
	methods: {
		async onToTop() {
			console.log('onToTop');
			if (this.isShowLoading) return;
			this.isShowLoading = true;
		},
		async onToBottom() {
			console.log('onToBottom');
		},
		async onItemResize() {},
		async onScroll(event) {
			//console.log(event);
			const chatListWrapperDom = document.querySelector('.virtList-content');
			const offsetY = this.$refs.virtListRef && this.$refs.virtListRef.getOffset();
			const targetOffsetY = Math.abs(offsetY) + chatListWrapperDom.clientHeight;

			console.log(targetOffsetY);
			let list = document.querySelectorAll('.virt-item'); // 查找所有view元素
			for (let i = 0; i < list.length; i++) {
				const item = list[i];
				//debugger;
				if (targetOffsetY >= item.offsetTop && targetOffsetY <= item.offsetTop + item.clientHeight) {
					// 取出id
					if (this.lastIndex === item.dataset.index) {
						return;
					}
					this.lastIndex = item.dataset.index;
					console.log('目标元素 item.dataset.index', item.dataset.index);
					console.log('目标元素 item.dataset.offsetTop', item.offsetTop);
					console.log('目标元素 item.dataset.maxOffsetY', item.offsetTop + item.clientHeight);
					break;
				}
			}
		},
		toBottomClick() {
			this.$refs.virtListRef?.scrollToBottom();
		},
		toPositionClick() {
			let timeout = setTimeout(() => {
				this.$refs.virtListRef?.scrollIntoView(50);
				clearTimeout(timeout);
				timeout = null;
			}, 20);
		}
	}
};
</script>

<style lang="scss" scoped>
.content {
	width: 100%;
	height: 100%;
	display: flex;
	flex-direction: column;
	.buttons-wrapper {
		display: flex;
		flex-direction: row;
		height: 8vmin;
	}
	.virtList-content {
		width: 100%;
		height: calc(100vmin - 11.73vmin - 8vmin);
	}
}
</style>

代码中我看在滚动中在获取当前index,其实可以通过内部的reaciveData中的renderBeigin获取

主要是获取刚刚出现在顶部dom,绑定在data-上的id

首次滚动到底部后,再定位到指定50位置时,不正确 image

确实存在问题。修复中,今天会发版

v1.0.5已解决该问题。pr内容:#8

default.mov

更新到最新版本了,滚动到指定位置还是有问题

首次滚动到底部后,再定位到指定50位置时,不正确 image

确实存在问题。修复中,今天会发版

v1.0.5已解决该问题。pr内容:#8

default.mov

更新到最新版本了,滚动到指定位置还是有问题

scrollIntoView滚动到指定位置有时候不太对

<template>
	<view class="content">
		<view class="buttons-wrapper">
			<view class="to-bottom" @click="toBottomClick">底部</view>
			<view class="to-position" @click="toPositionClick">定位</view>
		</view>
		<view class="virtList-content">
			<VirtList
				class="virtList"
				ref="virtListRef"
				:buffer="2"
				itemKey="id"
				:list="items"
				:minSize="20"
				@toTop="onToTop"
				@toBottom="onToBottom"
				@itemResize="onItemResize"
				@scroll="onScroll"
			>
				<template #default="{ itemData, index }">
					<view class="virt-item" :data-index="index">
						<view v-if="itemData.type === 0">{{ index }} - {{ itemData.text }}</view>
						<image v-if="itemData.type === 1" :src="itemData.text" />
					</view>
				</template>
				<template #header v-if="isShowLoading">
					<view style="width: 100%; height: 20px; display: flex; justify-content: center; align-items: center; background-color: chocolate">loading...</view>
				</template>
			</VirtList>
		</view>
	</view>
</template>

<script>
import { VirtList } from 'vue-virt-list';
// 这个稍
export default {
	components: { VirtList },
	data() {
		return {
			items: [],
			isShowLoading: false,
			lastIndex: null
		};
	},
	onLoad() {
		this.virtListRef = this.$refs.virtListRef;
		for (let i = 0; i < 1000; i++) {
			const item = { text: '', id: i, type: 0 };
			item.text = '测试内容';
			if (i % 2 === 0) {
				item.text = '测试内容测试内容测试内容测试内容测试内容测试内容测试内容测试内容测试内容测试内容测试内容测试内容测试内容测试内容测试内容测试内容';
			} else if (i % 5 === 0) {
				item.type = 1;
				item.text = 'https://newfile.ofweek.net/fileremote/msg/chat/2023-04/20230419175448321_dl.png';
			}
			this.items.push(item);
		}
		this.$nextTick(() => {
			this.$refs.virtListRef.scrollToBottom();
		});
	},
	methods: {
		async onToTop() {
			console.log('onToTop');
			if (this.isShowLoading) return;
			this.isShowLoading = true;
		},
		async onToBottom() {
			console.log('onToBottom');
		},
		async onItemResize() {},
		async onScroll(event) {
			//console.log(event);
			const chatListWrapperDom = document.querySelector('.virtList-content');
			const offsetY = this.$refs.virtListRef && this.$refs.virtListRef.getOffset();
			const targetOffsetY = Math.abs(offsetY) + chatListWrapperDom.clientHeight;

			console.log(targetOffsetY);
			let list = document.querySelectorAll('.virt-item'); // 查找所有view元素
			for (let i = 0; i < list.length; i++) {
				const item = list[i];
				//debugger;
				if (targetOffsetY >= item.offsetTop && targetOffsetY <= item.offsetTop + item.clientHeight) {
					// 取出id
					if (this.lastIndex === item.dataset.index) {
						return;
					}
					this.lastIndex = item.dataset.index;
					console.log('目标元素 item.dataset.index', item.dataset.index);
					console.log('目标元素 item.dataset.offsetTop', item.offsetTop);
					console.log('目标元素 item.dataset.maxOffsetY', item.offsetTop + item.clientHeight);
					break;
				}
			}
		},
		toBottomClick() {
			this.$refs.virtListRef?.scrollToBottom();
		},
		toPositionClick() {
			let timeout = setTimeout(() => {
				this.$refs.virtListRef?.scrollIntoView(50);
				clearTimeout(timeout);
				timeout = null;
			}, 20);
		}
	}
};
</script>

<style lang="scss" scoped>
.content {
	width: 100%;
	height: 100%;
	display: flex;
	flex-direction: column;
	.buttons-wrapper {
		display: flex;
		flex-direction: row;
		height: 8vmin;
	}
	.virtList-content {
		width: 100%;
		height: calc(100vmin - 11.73vmin - 8vmin);
	}
}
</style>

代码中我看在滚动中在获取当前index,其实可以通过内部的reaciveData中的renderBeigin获取

主要是获取刚刚出现在顶部dom,绑定在data-上的id

直接获取 this.$refs.virtListRef.reactiveData.inViewBegin,然后直接在元数据中拿到 list[this.$refs.virtListRef.reactiveData.inViewBegin]中你要的那个id,本身data-id就是源数据提供的