从零用java实现 小红书 springboot vue uniapp(13)模仿抖音视频切换

从零用java实现 小红书 springboot vue uniapp(13)实战:用Swiper+Video打造抖音式丝滑视频流

移动端演示 http://8.146.211.120:8081/#/

管理端演示 http://8.146.211.120:8088/#/

项目整体介绍及演示

前言

在上一篇文章中我们实现了视频笔记的发布功能,现在,我们将攻克一个更核心的体验功能:创建一个像抖音、快手那样的全屏、可上下滑动切换的视频信息流 。这不仅仅是UI的堆砌,背后涉及到 swipervideo 组件的深度联动、视频生命周期的精细化管理、以及数据预加载等关键技术。本文将详细拆解其实现过程。


核心技术实现

我们的目标是当用户向上或向下滑动时,上一个视频能自动暂停,下一个视频能自动播放,并且列表能无限滚动加载。我们将围绕 videoDetail.vue 文件来展开。

1. 基础布局:Swiper 与 Video 的结合

首先,我们搭建页面的骨架。外层使用 swiper 组件作为滑动容器,并设置其 vertical="true" 来实现垂直滚动。内部通过 v-for 循环渲染 swiper-item,每个 swiper-item 中放置一个全屏的 video 组件。

html 复制代码
<template>
    <swiper class="swiper-container" :vertical="true" @change="handleSwiperChange" :current="currentIndex">
        <swiper-item v-for="(video, index) in videoData" :key="video.noteId">
            <view class="video-container">
                <video 
                    class="video" 
                    :src="video.videoUrl"
                    :id="`video_${index}`" 
                    :loop="true"
                    :controls="false"
                    @timeupdate="handleTimeUpdate">
                </video>
                <!-- 其他UI元素,如点赞、评论按钮等 -->
            </view>
        </swiper-item>
    </swiper>
</template>
  • @change="handleSwiperChange":这是实现功能的核心,每当滑动切换视频时,该事件会被触发。
  • :id="'video_' + index":为每个video组件设置一个唯一的ID,这是后续通过代码精确控制视频播放/暂停的关键。
2. 视频播放控制:uni.createVideoContext

要用代码控制视频,我们必须先获取到每个视频的实例,即 VideoContext

我们在 data 中创建一个数组 videoContexts: [] 用于存储这些实例。然后,在页面数据加载并渲染完成后,初始化它们。

javascript 复制代码
// script
export default {
    data() {
        return {
            videoData: [],
            currentIndex: 0,
            videoContexts: []
        };
    },
    onReady() {
        // onReady生命周期确保了组件已渲染
        this.initVideoContexts();
    },
    methods: {
        initVideoContexts() {
            this.videoContexts = []; // 清空旧实例
            this.videoData.forEach((item, index) => {
                // 通过 video 的 id 创建并存储 context
                this.videoContexts[index] = uni.createVideoContext(`video_${index}`, this);
            });
            // 自动播放第一个视频
            if (this.videoContexts[this.currentIndex]) {
                this.videoContexts[this.currentIndex].play();
            }
        }
    }
}
3. 核心交互:滑动切换与自动播放

所有的关键都发生在 handleSwiperChange 方法中。当用户滑动 swiper 时,我们需要:

  1. 暂停上一个正在播放的视频。
  2. 播放当前显示的新视频。
javascript 复制代码
methods: {
    handleSwiperChange(event) {
        const { current } = event.detail;
        
        // 记录上一个视频的索引
        const previousIndex = this.currentIndex;

        // 暂停上一个视频
        if (this.videoContexts[previousIndex]) {
            this.videoContexts[previousIndex].pause();
        }

        // 更新当前视频的索引
        this.currentIndex = current;
        this.paused = false; // 重置手动暂停状态

        // 延时播放当前视频,确保滑动手势完成
        setTimeout(() => {
            if (this.videoContexts[this.currentIndex]) {
                this.videoContexts[this.currentIndex].play();
            }
        }, 250);
    },
}
4. 数据流:无限滚动与预加载

为了实现"刷不完"的效果,我们需要在用户快要滑到底部时,提前加载下一页的数据。

数据加载:

我们封装一个 loadVideos 方法,通过分页参数(page, pageSize)从后端获取视频列表,并追加到 videoData 数组中。

触发加载:

我们在 swiper 组件上监听 @scrolltolower 事件(在uniapp中,需要自己根据 currentIndex 模拟)。当用户滑动到倒数N个视频时(例如 preloadThreshold = 2),就调用 loadVideos

javascript 复制代码
// 在 handleSwiperChange 方法的最后调用
handleSwiperChange(event) {
    // ...上面的播放/暂停逻辑...
    
    // 检查是否需要加载更多视频
    this.checkAndLoadMore();
},

methods: {
    checkAndLoadMore() {
        // 当滑动到倒数第 preloadThreshold 个视频时,加载更多
        const isNearEnd = this.currentIndex >= this.videoData.length - this.preloadThreshold;
        
        if (isNearEnd && this.hasMore && !this.loading) {
            this.loadVideos(); // 该方法内部会请求API并追加数据
        }
    },

    loadVideos() {
        if(this.loading || !this.hasMore) return;
        this.loading = true;
        uni.app.get('/auth/getVideoNotes', { page: this.page, limit: this.pageSize }, '', (res => {
            // ...处理返回的数据...
            const newVideos = res.data.records || [];
            this.videoData = [...this.videoData, ...newVideos];
            this.hasMore = newVideos.length >= this.pageSize;
            this.page++;
            this.loading = false;
            
            // !! 关键:数据更新后,需要重新初始化新增的 video context
            this.$nextTick(() => {
                this.initVideoContexts();
            });
        }));
    }
}

注意: 每次加载新数据后,videoData 数组都变了,因此需要重新调用 initVideoContexts 来为新加入的视频创建 VideoContext 实例。


通过以上四步,我们就完整地实现了一个功能强大且体验流畅的抖音式视频流。

代码地址
https://gitee.com/ddeatrr/springboot_vue_xhs

相关推荐
在逃的吗喽10 分钟前
Vue3新变化
前端·javascript·vue.js
Terio_my11 分钟前
Spring Boot 热部署配置与禁用
java·spring boot·后端
青云交43 分钟前
Java 大视界 -- Java 大数据在智能安防视频监控系统中的视频语义理解与智能检索进阶
java·深度学习·监控系统·行为识别·智能安防·智能检索·视频语义理解
!chen1 小时前
如何在新的Spring Boot项目中关闭Spring Security?
java·spring·jar
Demoncode_y1 小时前
Vue3中基于路由的动态递归菜单组件实现
前端·javascript·vue.js·学习·递归·菜单组件
我是华为OD~HR~栗栗呀1 小时前
Java面经(22届考研-华oD)
java·后端·python·华为od·华为
茶憶1 小时前
uniapp 请求接口封装和使用
vue.js·uni-app
z晨晨2 小时前
互联网大厂Java求职面试实战:Spring Boot与微服务场景深度解析
java·spring boot·redis·微服务·kafka·spring security·电商
岁月宁静2 小时前
🎨 打造 AI 应用的 “门面”:Vue3.5 + MarkdownIt 实现高颜值、高性能的答案美化组件
前端·javascript·vue.js
码农飞哥2 小时前
AI编程开发系统001-基于SpringBoot+Vue的旅游民宿租赁系统
vue.js·spring boot·毕业设计·ai编程·计算机源码