前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >手把手教你用前端实现短视频App(滑动切换)

手把手教你用前端实现短视频App(滑动切换)

作者头像
Vam的金豆之路
发布2021-12-01 09:27:25
7130
发布2021-12-01 09:27:25
举报
文章被收录于专栏:前端历劫之路

前言

平常在玩短视频App时,喜欢看的视频可以多看一会,不喜欢看的视频直接往上一划,这个功能一直深受用户喜爱。今天我们不妨实现一个这样功能的App。

功能

  1. 上下滑动切换视频
  2. 可查看对应视频下的评论

示例

下面我挑出了几张代表性的图片,供大家参考。

下载链接

以上是我自己做的一款App的示例图,如果感兴趣的小伙伴,大家可以下载到手机上体验。目前只是开发了安卓版本。

代码语言:javascript
复制
链接: https://pan.baidu.com/s/1dbgx9eht54qh-Ig04w2JAg 
提取码: 96ta 
复制这段内容后打开百度网盘手机App,操作更方便哦

核心代码

代码语言:javascript
复制
<template>
  <div class="home">
    <van-swipe
      style="height: 100vh"
      vertical
      @change="onChange"
      :show-indicators="false"
    >
      <van-swipe-item>
        <div class="main" v-if="isshow">
          <video-player
            v-if="playerOptions.sources[0].src"
            class="video-player vjs-custom-skin"
            ref="videoPlayer"
            :playsinline="true"
            :options="playerOptions"
          ></video-player>
          <div class="footbox">
            <div class="foot">
              <p class="user">@ {{ artistName }}</p>
              <p class="name">{{ name }}</p>
            </div>
            <div class="pl" @click="openPl">
              <van-icon name="chat" size="30" />
            </div>
          </div>
        </div>
      </van-swipe-item>
      <van-swipe-item>
        <div class="main" v-if="!isshow">
          <video-player
            v-if="playerOptions.sources[0].src"
            class="video-player vjs-custom-skin"
            ref="videoPlayer"
            :playsinline="true"
            :options="playerOptions"
          ></video-player>
          <div class="footbox">
            <div class="foot">
              <p class="user">@ {{ artistName }}</p>
              <p class="name">{{ name }}</p>
            </div>
            <div class="pl" @click="openPl">
              <van-icon name="chat" size="30" />
            </div>
          </div>
        </div>
      </van-swipe-item>
    </van-swipe>
    <van-action-sheet v-model="show" class="sheet">
      <van-list
        v-model="loading"
        @load="onLoad"
        :offset="1"
        :immediate-check="false"
      >
        <div v-for="(item, index) in plist" :key="index" class="ovf pll">
          <div class="pl-l"><img :src="item.user.avatarUrl" alt="" /></div>
          <div class="pl-r">
            <div class="name1">{{ item.user.nickname }}</div>
            <div class="con">{{ item.content }}</div>
          </div>
        </div>
      </van-list>
    </van-action-sheet>
  </div>
</template>

<script>
import { list, mv, pl } from "@request/api";
import "../video/index";
import { videoPlayer } from "vue-video-player";
export default {
  name: "home",
  data() {
    return {
      list: "",
      id: "",
      show: false,
      dataLength: 1,
      inx: 0,
      artistName: "",
      name: "",
      isshow: true,
      plist: "",
      loading: false,
      page: 10,
      playerOptions: {
        autoplay: true, //如果true,浏览器准备好时开始回放。
        muted: false, // 默认情况下将会消除任何音频。
        loop: false, // 导致视频一结束就重新开始。
        preload: "auto", // 建议浏览器在<video>加载元素后是否应该开始下载视频数据。auto浏览器选择最佳行为,立即开始加载视频(如果浏览器支持)
        language: "zh-CN",
        poster:"",
        aspectRatio: "16:9", // 将播放器置于流畅模式,并在计算播放器的动态大小时使用该值。值应该代表一个比例 - 用冒号分隔的两个数字(例如"16:9"或"4:3")
        fluid: true, // 当true时,Video.js player将拥有流体大小。换句话说,它将按比例缩放以适应其容器。
        sources: [{ type: "video/mp4", src: "" }],
        width: document.documentElement.clientWidth,
        notSupportedMessage: "此视频暂无法播放,请稍后再试", //允许覆盖Video.js无法播放媒体源时显示的默认信息。
        controlBar: {
          timeDivider: true, // 分时
          durationDisplay: true, // 持续时间显示
          remainingTimeDisplay: false, // 剩余时间显示
          fullscreenToggle: false, //全屏按钮
        },
      },
    };
  },
  components: {
    videoPlayer,
  },
  mounted() {
    this.wait();
  },
  methods: {
    // 首次获取url
    async wait() {
      let id = await this.get();
      let res = await mv(id);
      // this.playerOptions.poster = this.poster;
      this.$set(this.playerOptions, "poster", this.poster);
      this.$set(this.playerOptions.sources[0], "src", res.data.url);
    },
    // 加载评论
    onLoad() {
      setTimeout(() => {
        this.page += 10;
        this.getpl();
        this.loading = false;
      }, 500);
    },
    // 获取数据
    get() {
      return list(this.dataLength).then((res) => {
        console.log(res.data);
        this.urlData = res.data;
        this.poster = this.urlData[this.inx].cover;
        this.id = this.urlData[this.inx].id;
        this.artistName = this.urlData[this.inx].artistName;
        this.name = this.urlData[this.inx].name;
        // return this.id;
        return Promise.resolve(this.id);
        // 等价于
        // return new Promise((resolve) => {
        //   resolve(this.id)
        // })
      });
    },
    // 封装静态数据
    getStatic(v) {
      this.id = v[this.inx].id;
      this.artistName = v[this.inx].artistName;
      this.name = v[this.inx].name;
      this.poster = v[this.inx].cover;
      return this.id;
    },
    // 获取评论
    getpl() {
      pl(this.id, this.page).then((res) => {
        if (document.querySelector(".van-action-sheet__content")) {
          document.querySelector(".van-action-sheet__content").scrollTop = 0;
        }
        this.plist = res.comments;
      });
    },
    // 滑动触发
    async onChange() {
      console.log(this.inx);
      this.isshow = !this.isshow;
      this.page = 10;
      this.getpl();
      if (this.inx < this.urlData.length - 1) {
        this.inx += 1;
        let id = this.getStatic(this.urlData);
        let res = await mv(id);
        this.$set(this.playerOptions.sources[0], "src", res.data.url);
        this.$set(this.playerOptions, "poster", this.poster);
        // this.playerOptions.poster = this.poster;
      } else {
        this.inx = 0;
        this.dataLength += 1;
        this.wait();
      }
    },
    // 打开评论列表
    openPl() {
      this.show = true;
      this.getpl();
    },
  },
};
</script>
<style lang="less" scoped>
.main {
  height: 100%;
}
.footbox {
  position: relative;
  bottom: 0;
  width: 95%;
  margin: 0 auto;
  display: flex;
  justify-content: space-between;
  align-items: center;
}
.user {
  font-size: 14px;
}
.user,
.name {
  text-overflow: ellipsis;
  overflow: hidden;
  white-space: nowrap;
}
.foot {
  width: 80%;
  color: #fff;
  font-size: 16px;
  z-index: 10001;
}
.pl {
  width: 10%;
  color: #fff;
  font-size: 16px;
  z-index: 10001;
}
.sheet {
  height: 50vh;
  .pll {
    overflow: hidden;
    padding: 10px;
    border-bottom: 1px solid #f4f4f4;
    .pl-l {
      width: 20%;
      float: left;
    }
    .pl-l img {
      width: 55%;
      border-radius: 50%;
      animation: all ds 0.5s;
    }
    @keyframes ds {
      from {
        opacity: 0;
      }
      to {
        opacity: 1;
      }
    }
    .pl-r {
      width: 78%;
      float: left;
    }
    .name1 {
      font-size: 14px;
      color: #666;
      font-weight: bold;
      margin-bottom: 5px;
    }
    .con {
      width: 100%;
      line-height: 24px;
      color: #333333;
      font-size: 14px;
    }
  }
}
</style>

完整代码库

恭请各位大佬指正。

代码语言:javascript
复制
https://github.com/maomincoding/zm_mv2
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-11-12,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 前端历劫之路 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 功能
  • 示例
  • 下载链接
  • 核心代码
  • 完整代码库
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档