前言
平常在玩短视频App时,喜欢看的视频可以多看一会,不喜欢看的视频直接往上一划,这个功能一直深受用户喜爱。今天我们不妨实现一个这样功能的App。
功能
- 上下滑动切换视频
- 可查看对应视频下的评论
示例
下面我挑出了几张代表性的图片,供大家参考。
下载链接
以上是我自己做的一款App的示例图,如果感兴趣的小伙伴,大家可以下载到手机上体验。目前只是开发了安卓版本。
- 链接: https://pan.baidu.com/s/1dbgx9eht54qh-Ig04w2JAg
- 提取码: 96ta
- 复制这段内容后打开百度网盘手机App,操作更方便哦
核心代码
- <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>
完整代码库
恭请各位大佬指正。
https://github.com/maomincoding/zm_mv2