Skip to content

仿抖音小程序短视频组件-基于uniapp+vue3+typescript

Notifications You must be signed in to change notification settings

akFace/uniapp-tiktok

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Mar 27, 2024
9734663 · Mar 27, 2024

History

11 Commits
Mar 27, 2024
Jun 13, 2023
Mar 27, 2024
Jun 13, 2023
Jun 13, 2023
Jun 13, 2023
Jun 13, 2023

Repository files navigation

基于 uniapp 开发的仿抖音小程序组件(超高性能)

GIF 截图效果

  • GIF 帧率不够,实际真机效果非常丝滑

注:组件使用 vue3+typescript 开发

  • 全局仅渲染 3 个 swiper-item
  • 实测,不管加载多少数据也能丝滑滚动
  • 适用于 vue3,vue2 请自行修
  • 自动预加载视频
  • 首次渲染优化

快速开始,下载插件后请按照此方法运行调试

  1. 安装 nodejs: https://nodejs.org/en/
  2. 安装依赖: npm i
  3. 运行项目: npm run dev:mp-weixin
  4. 构建项目资源: npm run build:mp-weixin
  5. 打开小程序开发工具导入dist/dev/mp-weixin 即可
  6. 真机预览,请点小程序开发工具上的预览,扫码真机预览即可

参考 API

属性 类型 默认值 说明
videoList Array - 视频列表,数组对象 {src: string, poster?: string, objectFit?: string}
autoObjectFit Boolean true 是否开启视频自动自适应平铺模式,竖屏全屏覆盖,横屏自适应居中, 此参数优先级低于 videoList 中的 objectFit
loop Boolean true 是否循环播放视频
controls Boolean false 显示原生控制栏
autoplay Boolean true 是否自动播放
autoChange Boolean false 是否自动滚动播放
loadMoreOffsetCount Number 2 滚动加载阈值(即播放到剩余多少个之后触发加载更多
@play EventHandle - 当开始/继续播放时触发 play 事件
@error EventHandle - 视频播放出错时触发
@ended EventHandle - 当播放到末尾时触发 ended 事件
@loadMore EventHandle - 当滚动到最后第 N 条数据后,需要加载更多时触发
@change EventHandle - 切换视频时触发
@click EventHandle - 点击整个视频区域触发
@controlstoggle EventHandle - 控制栏状态变化触发

Slots 插槽

属性 默认值 说明
default - 自定义内容,覆盖到视频上方的所有自定义内容 v-slot="data" 为当前渲染数据,请参照使用示例

方法

// 播放第几个视频
mTikTokRef.value?.initSwiperData(index);

// 播放与暂停
mTikTokRef.value?.togglePlay();

// 播放跳转到指定位置,单位 s
mTikTokRef.value?.playSeeked(8);

使用示例

<template>
  <div class="video-container">
    <mTikTok
      ref="mTikTokRef"
      :video-list="state.videoList"
      @loadMore="loadMore"
      @change="change"
    >
      <!-- 此处为用户完全自定义 data 中的数据为当前渲染的数据 -->
      <template v-slot="data">
        <!-- active修复视频悬浮层消失和点击的问题 -->
        <view
          class="video-side-right"
          :class="{ active: state.cutVideo.id === data.item.id }"
        >
          <view class="action-item action-item-user">
            <image
              class="shop-logo"
              src="https://examples-1251000004.cos.ap-shanghai.myqcloud.com/sample.jpeg?imageMogr2/crop/180x180/gravity/center"
            />
            <view class="action-btn">
              <text class="iconfont">+</text>
            </view>
            <text class="action-item-text"></text>
          </view>
          <view class="action-item">
            <text class="iconfont icon-star11beifen"></text>
            <text class="action-item-text">{{ data.item.id }}</text>
          </view>
          <view class="action-item">
            <text class="iconfont icon-share"></text>
            <text class="action-item-text">分享</text>
          </view>
        </view>
        <!-- active修复视频悬浮层消失和点击的问题 -->
        <view
          class="video-bottom-area"
          :class="{ active: state.cutVideo.id === data.item.id }"
        >
          <view class="shop-name"> @{{ data.item.name }} </view>
          <view class="shop-card">{{ data.item.desc }}</view>
        </view>
      </template>
    </mTikTok>
  </div>
</template>
<script lang="ts" setup>
import { onMounted, reactive, ref } from "vue";
// 导入组件
import mTikTok from "@/components/mTikTok.vue";

const mTikTokRef = ref<InstanceType<typeof mTikTok>>();

const state = reactive({
  cutVideo: {} as AnyObject,
  videoList: [
    {
      src: "https://xjc.demo.hongcd.com/uploads/20230214/84e165388f5bfdb1550522f50f5a57bb.mp4",
      id: "1",
      name: "开玩笑的鸡毛",
      desc: "这里是简介内容",
    },
    {
      src: "https://xjc.demo.hongcd.com/uploads/20230214/3f26d950ac286eecedba49f5295f0819.mp4",
      id: "2",
      name: "开玩笑的鸡毛",
      desc: "这里是简介内容",
    },
    {
      src: "https://xjc.demo.hongcd.com/uploads/20230215/8b5ac0420fe61e2f9660d7b8af998f7b.mp4",
      id: "3",
      name: "开玩笑的鸡毛",
      desc: "这里是简介内容",
    },
    {
      src: "https://xjc.demo.hongcd.com/uploads/20210128/d932b2d78cebb0a8cb8f9a6216790dfb.mp4",
      id: "4",
      name: "开玩笑的鸡毛",
      desc: "这里是简介内容",
    },
    {
      src: "https://xjc.demo.hongcd.com/uploads/20210128/0c64cbeea28b10c06eee8728c762449e.mp4",
      id: "5",
      name: "开玩笑的鸡毛",
      desc: "这里是简介内容",
    },
    {
      src: "https://xjc.demo.hongcd.com/uploads/20210327/1b72e1b6153cd29df07f5449991e8083.mp4",
      id: "6",
      name: "开玩笑的鸡毛",
      desc: "这里是简介内容",
    },
    {
      src: "https://xjc.demo.hongcd.com/uploads/20230214/7e1a0baaebc4e656bbbfbc44d7a55a60.mp4",
      id: "7",
      name: "开玩笑的鸡毛",
      desc: "这里是简介内容",
    },
  ],
});

const loadMore = () => {
  // 触发加载更多
  console.log("加载更多");
};

const change = (e: any) => {
  state.cutVideo = e.detail;
  console.log("🚀 ~ file: index.vue:53 ~ change ~ data:", e);
};

// 播放第几个
const playIndex = (index: number) => {
  mTikTokRef.value?.initSwiperData(index);
};

onMounted(() => {
  // 直接播放第3个
  // playIndex(3);
});
</script>
<style lang="scss">
$zIndex: 99;

.video-layer {
  position: absolute;
  right: 12px;
  bottom: 120px;
  color: #fff;
}

.video-bottom-area {
  position: absolute;
  left: 20px;
  bottom: 40px;
  opacity: 0;
  transition: all 250ms;
  z-index: 0;

  &.active {
    opacity: 1;
    z-index: $zIndex;
    transition-delay: 200ms;
  }

  .shop-name {
    color: #fff;
    margin-bottom: 6px;
  }

  .shop-card {
    width: 160px;
    height: 80px;
    background-color: rgba(255, 255, 255, 0.5);
    border-radius: 4px;
  }
}

.video-side-right {
  position: absolute;
  right: 12px;
  bottom: 120px;
  color: #fff;
  opacity: 0;
  transition: all 250ms;
  z-index: 0;

  &.active {
    opacity: 1;
    z-index: $zIndex;
    transition-delay: 200ms;
  }

  .action-item {
    position: relative;
    margin-bottom: 20px;
    text-align: center;

    .shop-logo {
      width: 40px;
      height: 40px;
      border-radius: 50%;
      overflow: hidden;
    }

    .iconfont {
      display: block;
      font-size: 28px;
    }

    .action-item-text {
      display: block;
      font-size: 12px;
    }

    .action-btn {
      position: absolute;
      left: 50%;
      transform: translateX(-50%);
      bottom: -8px;
      width: 20px;
      height: 20px;
      border-radius: 50%;
      display: flex;
      align-items: center;
      justify-content: center;
      background-color: #f60;

      .iconfont {
        font-size: 16px;
      }
    }
  }

  .action-item-user {
    margin-bottom: 40px;
  }
}
</style>

About

仿抖音小程序短视频组件-基于uniapp+vue3+typescript

Topics

Resources

Stars

Watchers

Forks

Packages

No packages published