文章目录
- 1. 实现效果
- 2. 精简版核心代码
- 3. 完整功能点(本文章不写,只写核心代码)
1. 实现效果
2. 精简版核心代码
- 使用的
vue3
+ vant4
组件 - 使用
van-swipe
进行轮播图切换实现
<template>
<div :style="{
width: width + 'px',
overflow: 'hidden',
}" class="container">
<van-swipe :loop="true" vertical :height="height" :width="width" :show-indicators="false" @change="onChange"
:style="{ height: height + 'px' }">
<van-swipe-item v-for="(item, index) in videoList" :key="index" class="swiper-slide-item">
<div @click="onVideoClick(item, index)" z-index="1" class="swiperItemVideo">
<video class="videoPlayer" :id="'videoPlayer_' + index" ref="player" :key="index" :poster="item.poster"
:src="item.src" :width="width" autoplay :muted="muteding" loop x5-video-player-type="h5"
webkit-playsinline="true" x-webkit-airplay="true" x5-video-orientation="portraint"
playsInline="true" x5-video-player-fullscreen="portraint" x5-video-ignore-metadata='true'></video>
<van-image v-if="!playing" class="play w-[40px] h-[40px]" :src="getAssetsFile('icon/play.png')" />
</div>
<ShortsBottom ref="bottomRef" :item="item" />
</van-swipe-item>
</van-swipe>
</div>
</template>
<script setup lang="ts" name="Setting">
import {
getAssetsFile
} from '@/utils/tool'
const player = ref(null);
const currentIndex = ref(0);
const playing = ref(true);
const muteding = ref(true)
const width = ref(window.innerWidth);
const height = ref(window.innerHeight);
let bottomRef = ref(null)
let bottomHeight = ref(0);
const currentVideoInfo = ref({
videoId: "",
});
const onChange = (index) => {
console.log(index, "index")
currentVideoInfo.value = {
videoId: ""
};
const preVideoId = "videoPlayer_" + currentIndex.value;
const preVideo: any = document.getElementById(preVideoId);
if (preVideo) preVideo.pause();
const nextVideoId = "videoPlayer_" + index;
const nextVideo: any = document.getElementById(nextVideoId);
if (nextVideo) nextVideo.play();
currentIndex.value = index;
player.value = nextVideo;
playing.value = true
if (index == videoList.length - 1) {
console.log("没有更多了")
}
};
const onVideoClick = (item, index) => {
const video: any = document.getElementById("videoPlayer_" + index);
if (video && playing.value) {
video.pause();
playing.value = false;
} else {
video.play();
playing.value = true;
}
};
onMounted(() => {
if (bottomRef.value) {
console.log(bottomRef.value[0].bottomHeight, 1)
bottomHeight.value = bottomRef.value[0].bottomHeight
}
const index = currentIndex.value;
const videos: any = document.querySelectorAll("video");
for (const video of videos) {
let videoId = "videoPlayer_" + index;
if (video && video.id && video.id != videoId) {
video.pause();
} else {
player.value = video;
}
}
});
onBeforeUnmount(() => {
const videos: any = document.querySelectorAll("video");
for (const video of videos) {
if (video && video.id) {
video.pause();
}
}
});
const videoList = [{
videoId: Date.now() + 1,
title: "抖音美女主播,JK超短裙学生妆美女跳舞展示,爱了爱了。",
poster: "http://img01.sogoucdn.com/app/a/201023/27e5400e26fbef1ea32f9aff60c0b015",
src: "https://txmov2.a.yximgs.com/upic/2020/11/08/19/BMjAyMDExMDgxOTQxNTlfNTIzNDczMzQ0XzM4OTQ1MDk5MTI4XzFfMw==_b_Bc770a92f0cf153407d60a2eddffeae2a.mp4",
uploadTime: "2023-11-08 19:41",
ipLocation: "上海",
author: {
authorId: 101,
avatar: "https://i02piccdn.sogoucdn.com/4f85fc70df81d04a",
nickName: "陌路",
genderName: "男"
}
},
{
videoId: Date.now() + 2,
title: "御姐美女抖音作品,来个自拍视频把,好美啊。",
poster: "http://img02.sogoucdn.com/app/a/201023/0866f6a339e58d647eb476f72045e980",
src: "https://txmov2.a.yximgs.com/upic/2020/10/02/09/BMjAyMDEwMDIwOTAwMDlfMTIyMjc0NTk0Ml8zNjk3Mjg0NjcxOF8xXzM=_b_B28a4518e86e2cf6155a6c1fc9cf79c6d.mp4",
uploadTime: "2023-10-02 09:41",
ipLocation: "贵州",
author: {
authorId: 102,
avatar: "http://img02.sogoucdn.com/app/a/201023/0866f6a339e58d647eb476f72045e980",
nickName: "御姐呀",
genderName: "女"
}
},
{
videoId: Date.now() + 3,
title: "抖音主播可爱妹子新学的舞蹈,超可爱的美女主播。",
poster: "https://i02piccdn.sogoucdn.com/2acf176d90718d73",
src: "https://txmov6.a.yximgs.com/upic/2020/08/23/00/BMjAyMDA4MjMwMDMyNDRfMTYzMzY5MDA0XzM0ODI4MDcyMzQ5XzFfMw==_b_B9a1c9d4e3a090bb2815994d7f33a906a.mp4",
uploadTime: "2023-08-23 00:41",
ipLocation: "广州",
author: {
authorId: 103,
avatar: "https://i02piccdn.sogoucdn.com/2acf176d90718d73",
nickName: "野花猫",
genderName: "女"
}
},
{
videoId: Date.now() + 4,
title: "多个美女带着遮阳帽出去散步自拍视频,好好看。",
poster: "https://i02piccdn.sogoucdn.com/45c34c84c106bbb7",
src: "https://alimov2.a.yximgs.com/upic/2020/07/02/14/BMjAyMDA3MDIxNDUyMDlfOTExMjIyMjRfMzE1OTEwNjAxNTRfMV8z_b_Bf3005d42ce9c01c0687147428c28d7e6.mp4",
uploadTime: "2023-07-02 14:41",
ipLocation: "山西",
author: {
authorId: 104,
avatar: "https://i02piccdn.sogoucdn.com/45c34c84c106bbb7",
nickName: "蓝姬",
genderName: "女"
}
},
];
</script>
<style lang="less" scoped>
.container {
display: flex;
flex-direction: column;
overflow: hidden;
.swiper-wrapper {
flex: 1;
}
.swiper-slide-item {
display: flex;
flex-direction: column;
width: 100%;
.swiperItemVideo {
z-index: 1;
flex: 1;
overflow-y: auto;
width: 100%;
position: relative;
.play {
position: absolute;
z-index: 2;
content: "";
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
animation: move 0.3s linear alternate;
}
}
.videoPlayer {
background: #000;
height: 100%;
z-index: 2;
}
}
}
@keyframes move {
0% {
transform: translate(-50%, -50%) scale(2);
opacity: 0;
}
100% {
transform: translate(-50%, -50%) scale(1);
opacity: 1;
}
}
</style>
- ShortsBottom 组件代码
<template>
<div class="videoInfo" ref="bottomRef">
<div class="top mb-[8px]">
<van-image class="logo w-[40px] h-[40px] mr-[8px]" round :src="getAssetsFile('logo.png')" />
<span class="nickName mr-[12px]">{{ item.author.nickName }}</span>
<div class="btn-content" @click="Follow">
<van-button type="primary" size="small" class="btn">Follow</van-button>
</div>
<div class="closeSound">
<van-image class="logo w-[16px] h-[16px]" :src="getAssetsFile('icon/closeSound.png')" />
</div>
</div>
<van-text-ellipsis class="title" :content="item.title" />
</div>
</template>
<script setup lang="ts">
import { ref, onMounted } from "vue";
import { getAssetsFile } from '@/utils/tool'
interface Props {
item : any;
}
const props = withDefaults(defineProps<Props>(), {
item: {},
});
let bottomRef = ref(null)
let bottomHeight = ref(0)
const Follow = ()=>{
console.log("关注")
}
onMounted(() => {
if (bottomRef.value) {
bottomHeight.value = bottomRef.value.offsetHeight
}
});
defineExpose({ bottomHeight })
</script>
<style lang="less" scoped>
.videoInfo {
background: #161616;
color: #f5f5f5;
padding: 16px 20px 34px 16px;
text-align: left;
position: relative;
&::after {
position: absolute;
display: block;
content: "";
bottom: 0px;
left: 0;
width: 100%;
height: 0px;
background: red;
z-index: 1;
}
.top {
display: flex;
justify-content: flex-start;
align-items: center;
.nickName {
font-family: HarmonyOS Sans SC, HarmonyOS Sans SC;
font-weight: 700;
font-size: 14px;
color: #FFFFFF;
line-height: 14px;
}
.closeSound {
margin-left: auto;
width: 32px;
height: 32px;
padding: 8px;
border-radius: 50%;
background: rgba(255, 255, 255, 0.1);
}
}
.title {
font-family: HarmonyOS Sans SC, HarmonyOS Sans SC;
font-weight: 400;
font-size: 14px;
color: #FFFFFF;
line-height: 14px;
}
}
</style>
3. 完整功能点(本文章不写,只写核心代码)
- 视频点赞
- 视频分享
- 视频用户基础信息
- 视频暂停/播放
- 视频声音控制
- 上下切换视频
- 视频封面图设置