更新记录

1.0.3(2024-12-14) 下载此版本

数据结构修改

// 除id,cover外,其余内部参数均存放在item.detail下
// 比如下面是你的视频列表
const videoList = [
    {
        id:'xxx', 
        cover:'xxx', // 等等
        // 组件内字段
        detail:{ // 在传入组件时会自动初始化
            paused: true, // 是否暂停
            loaded: false, //视频是否加载完毕
            rate: 1, // 播放速度
            duration: 0,
            currentTime: 0,
        }
    }
]

示例项目增加功能

示例项目中的代码为了方便和快捷并没有考虑任何优化,只可以参考其实现逻辑和想法,不能直接使用到自己项目。

  • 长按屏幕倍速播放
  • 视频进度,拖动进度

1.0.2(2024-12-10) 下载此版本

  • 优化界面展示效果以及示例代码完整性
  • 优化操作逻辑

1.0.1(2024-12-10) 下载此版本

更新示例代码

查看更多

平台兼容性

Vue2 Vue3
×
App 快应用 微信小程序 支付宝小程序 百度小程序 字节小程序 QQ小程序
HBuilderX 4.36 × × × × ×
钉钉小程序 快手小程序 飞书小程序 京东小程序 鸿蒙元服务
× × × × ×
H5-Safari Android Browser 微信浏览器(Android) QQ浏览器(Android) Chrome IE Edge Firefox PC-Safari
× × × × × × × × ×

简介

video-swiper一个基于 swiper 嵌套 video 实现仿抖音短视频组件,目前仅支持 H5、微信小程序

使用说明

建议运行示例工程,熟悉一下代码,有问题可以在问我

<template>
    <view class="content">
        <!-- 可能需要处理状态栏 -->

        <view class="refresh">下拉刷新 </view>
        <video-swiper :videos="videos" @refresh="onRefresh" @change="onChange">
            <!-- 自定义loading -->
            <template v-slot:loading>
                <view class="loading full flex center"> 自定义loading </view>
            </template>

            <!-- 默认插槽 -->
            <template v-slot="{ data }">
                <view class="right-area">
                    id: {{ data.id }}
                    我是右侧区域
                </view>
                <view class="bottom-area"> 我是底部区域 </view>
            </template>
        </video-swiper>
        <!-- 自己加动画效果,比如全屏转圈 -->
        <!-- loading的时间就是家口请求的时间,有问题就加延迟 -->
        <view class="loadmore"> 加载更多 </view>
    </view>
</template>

<script setup>
    import {
        ref
    } from "vue";
    import videoSwiper from "@/uni_modules/cc-swiper-video/index.vue";
    import cover from '@/static/cover.jpeg'

    // 视频列表,这里只存储当前页的视频即可,组件内部会的处理
    // 自己的代码逻辑只需要处理pageIndex和pageSize即可
    const videos = ref([]);

    // 应该一次性获取多条视频链接
    // 然后合适的时候往视频数组中push
    let id = 0;
    const getVideos = async () => {
        return new Promise((r) => {
            // setTimeout(() => {
            //  videos.value = [{
            //      id: '123',
            //      url: 'http://127.0.0.1:8080/%E6%93%8D%E4%BD%9C%E8%A7%86%E9%A2%91.mp4',
            //      cover
            //  }]
            //  r();
            // }, 1000)
            // return
            // const ip = "http://127.0.0.1:3000";
            // 真机调试可以填入局域网地址
            const ip = 'http://192.168.1.6:3000'
            uni.request({
                url: `${ip}/getVideo`,
                success(res) {
                    const list = res.data.data;
                    videos.value = list.map((url, index) => {
                        return {
                            url,
                            id: ++id,
                            cover, // 视频封面,应该是视频的第一帧,不传的话会默认显示loading
                        };
                    });

                    r();
                },
            });
        });
    };

    const onChange = async ({
        videoIndex, // 当前的index
        videoCount, // 所有的视频长度
    }) => {
        return
        // 剩余4个视频的时候后台加载更多
        // 如果使用这个方法,需要在onRefresh中当isInitLoad为flase时return
        // 需要自己添加一个flag,防止多次请求数据
        if (videoCount - videoIndex < 4) {
            await getVideos()
        }
    };

    // 初始化视频或者加载数据
    // 这里只需要请求数据就可以了,组件内部会处理的
    const onRefresh = async ({
        finish,
        isInitLoad
    }) => {
        // 如果是无限滚动方式解除“if(!isInitLoad)return ”代码注释走onChange逻辑
        // 否则不走onChange代码,走上拉加载
        // if(!isInitLoad)return 
        if (isInitLoad) {
            id = 0
        }
        // 可以使用isInitLoad判断是刷新还是加载更多
        // 上划加载或者初次加载数据
        await getVideos();
        finish && finish();
    };
</script>

<style lang="scss" scoped>
    .content {
        width: 100vw;
        height: 100vh;
        background: green;
    }

    .full {
        width: 100%;
        height: 100%;
    }

    .flex {
        display: flex;
    }

    .justify-center {
        justify-content: center;
    }

    .items-center {
        align-items: center;
    }

    .center {
        justify-content: center;
        align-items: center;
    }

    .loading {
        position: relative;
        background: rgba(0, 0, 0, 1);
        color: white;
    }

    .right-area {
        writing-mode: vertical-lr;
        position: absolute;
        z-index: 999;
        right: 0;
        bottom: 200rpx;
        padding: 20rpx;
        background: red;
    }

    .bottom-area {
        position: absolute;
        z-index: 999;
        width: 100%;
        height: 100rpx;
        right: left;
        bottom: 0;
        background: pink;
    }

    .refresh {
        position: absolute;
        top: 30rpx;
        width: 100%;
        display: flex;
        justify-content: center;
        align-items: center;
    }

    .loadmore {
        position: absolute;
        bottom: 30rpx;
        width: 100%;
        display: flex;
        justify-content: center;
        align-items: center;
    }

    ::v-deep .uni-video-container {
        // 重写h5下的背景。如果有封面图可以改成毛玻璃的形式
        background: black;
    }
</style>

注意事项

  • 如果没有视频接口可以使用 node 运行 server/index.js
    这也是我网上找的api,代码里注释了原文地址
  • 视频列表中的每项必须包括 url、id 字段,其他的预留字段
    1. cover::封面
    2. paused:是否暂停
    3. loaded:视频是否加载完毕
  • 微信小程序切换首尾视频时会闪一下
    如果视频条数不是3的倍数,然后使用上拉加载,组件内会处理一下当前的swiper的current,否则circular会有问题
    如果不能接受请使用无限加载,或者接口返回的条数是3的倍数

隐私、权限声明

1. 本插件需要申请的系统权限列表:

2. 本插件采集的数据、发送的服务器地址、以及数据用途说明:

3. 本插件是否包含广告,如包含需详细说明广告表达方式、展示频率:

许可协议

MIT协议

暂无用户评论。

使用中有什么不明白的地方,就向插件作者提问吧~ 我要提问