vue实现视频下滑
Vue 实现视频下滑功能
实现视频下滑功能通常涉及监听滚动事件、动态加载视频内容以及优化性能。以下是具体实现方法:

监听滚动事件
在 Vue 中可以通过 @scroll 事件监听滚动行为,结合 scrollTop 和 clientHeight 判断是否到达底部。

<template>
<div class="video-container" @scroll="handleScroll">
<div v-for="(video, index) in videos" :key="index">
<video :src="video.src" controls></video>
</div>
</div>
</template>
<script>
export default {
data() {
return {
videos: [],
currentPage: 1,
isLoading: false
};
},
methods: {
handleScroll(event) {
const container = event.target;
const scrollBottom = container.scrollHeight - container.scrollTop - container.clientHeight;
if (scrollBottom < 100 && !this.isLoading) {
this.loadMoreVideos();
}
},
loadMoreVideos() {
this.isLoading = true;
// 模拟异步加载
setTimeout(() => {
const newVideos = [...Array(5)].map((_, i) => ({
src: `https://example.com/video${this.currentPage + i}.mp4`
}));
this.videos = [...this.videos, ...newVideos];
this.currentPage += 5;
this.isLoading = false;
}, 1000);
}
},
mounted() {
this.loadMoreVideos();
}
};
</script>
<style>
.video-container {
height: 100vh;
overflow-y: auto;
}
video {
width: 100%;
margin-bottom: 20px;
}
</style>
使用 Intersection Observer API
Intersection Observer 更高效,适合监听元素是否进入视口。
<template>
<div class="video-container">
<div v-for="(video, index) in videos" :key="index" ref="videoItems">
<video :src="video.src" controls></video>
</div>
<div ref="loader" v-if="isLoading">Loading...</div>
</div>
</template>
<script>
export default {
data() {
return {
videos: [],
currentPage: 1,
isLoading: false,
observer: null
};
},
methods: {
initObserver() {
this.observer = new IntersectionObserver((entries) => {
if (entries[0].isIntersecting && !this.isLoading) {
this.loadMoreVideos();
}
}, { threshold: 0.1 });
this.observer.observe(this.$refs.loader);
},
loadMoreVideos() {
this.isLoading = true;
setTimeout(() => {
const newVideos = [...Array(5)].map((_, i) => ({
src: `https://example.com/video${this.currentPage + i}.mp4`
}));
this.videos = [...this.videos, ...newVideos];
this.currentPage += 5;
this.isLoading = false;
}, 1000);
}
},
mounted() {
this.loadMoreVideos();
this.$nextTick(() => {
this.initObserver();
});
},
beforeDestroy() {
if (this.observer) {
this.observer.disconnect();
}
}
};
</script>
优化性能
- 懒加载视频:使用
loading="lazy"属性或动态设置src。 - 虚拟滚动:对于大量视频,使用
vue-virtual-scroller等库减少 DOM 数量。 - 节流滚动事件:避免频繁触发加载逻辑。
import { throttle } from 'lodash';
export default {
methods: {
handleScroll: throttle(function(event) {
const container = event.target;
const scrollBottom = container.scrollHeight - container.scrollTop - container.clientHeight;
if (scrollBottom < 100 && !this.isLoading) {
this.loadMoreVideos();
}
}, 200)
}
};
完整示例代码
结合上述方法,以下是一个完整的实现:
<template>
<div class="video-container" @scroll="handleScroll">
<div v-for="(video, index) in videos" :key="index">
<video :src="video.src" controls :poster="video.poster"></video>
</div>
<div v-if="isLoading" class="loading">Loading more videos...</div>
</div>
</template>
<script>
import { throttle } from 'lodash';
export default {
data() {
return {
videos: [],
currentPage: 1,
isLoading: false,
hasMore: true
};
},
methods: {
handleScroll: throttle(function(event) {
const container = event.target;
const scrollBottom = container.scrollHeight - container.scrollTop - container.clientHeight;
if (scrollBottom < 100 && !this.isLoading && this.hasMore) {
this.loadMoreVideos();
}
}, 200),
async loadMoreVideos() {
this.isLoading = true;
try {
const newVideos = await this.fetchVideos(this.currentPage);
if (newVideos.length === 0) {
this.hasMore = false;
} else {
this.videos = [...this.videos, ...newVideos];
this.currentPage += 1;
}
} catch (error) {
console.error('Failed to load videos:', error);
} finally {
this.isLoading = false;
}
},
fetchVideos(page) {
return new Promise((resolve) => {
setTimeout(() => {
resolve(
[...Array(5)].map((_, i) => ({
src: `https://example.com/video${page + i}.mp4`,
poster: `https://example.com/thumbnail${page + i}.jpg`
}))
);
}, 1000);
});
}
},
mounted() {
this.loadMoreVideos();
}
};
</script>
<style>
.video-container {
height: 100vh;
overflow-y: auto;
}
video {
width: 100%;
margin-bottom: 20px;
}
.loading {
text-align: center;
padding: 10px;
}
</style>






