Vue3.0短视频+直播|vue3+vite2+vant3仿抖音界面|vue3.x小视频实例

时间:2023-12-24 22:49:31

基于vue3.0构建移动端仿抖音/快手短视频+直播实战项目Vue3-DouYin

5G时代已来,短视频也越来越成为新一代年轻人的娱乐方式,在这个特殊之年,又将再一次成为新年俗!

基于vue3.x+vite2+vuex4+vue-router+vant3+v3popup等技术搭建开发仿抖音App界面小视频/直播/聊天实例项目。实现短视频上下左右滑动切换、点赞/评论/聊天/红包及送礼物等功能。

Vue3.0短视频+直播|vue3+vite2+vant3仿抖音界面|vue3.x小视频实例

一、运用技术

  • 编码器:VScode/Notepad++
  • 使用技术:Vue3.x+Vuex4.x+Vue-Router4
  • 组件库:Vant^3.0.4 (有赞移动端vue3组件库)
  • 弹层组件:V3Popup(基于vue3自定义弹层组件)
  • 字体图标:阿里iconfont图标库
  • 导航栏+标签栏:基于vue3自定义navbar/tabbar组件

Vue3.0短视频+直播|vue3+vite2+vant3仿抖音界面|vue3.x小视频实例

二、项目目录结构

Vue3.0短视频+直播|vue3+vite2+vant3仿抖音界面|vue3.x小视频实例

◆ 效果预览

Vue3.0短视频+直播|vue3+vite2+vant3仿抖音界面|vue3.x小视频实例

Vue3.0短视频+直播|vue3+vite2+vant3仿抖音界面|vue3.x小视频实例

Vue3.0短视频+直播|vue3+vite2+vant3仿抖音界面|vue3.x小视频实例

Vue3.0短视频+直播|vue3+vite2+vant3仿抖音界面|vue3.x小视频实例

Vue3.0短视频+直播|vue3+vite2+vant3仿抖音界面|vue3.x小视频实例

Vue3.0短视频+直播|vue3+vite2+vant3仿抖音界面|vue3.x小视频实例

Vue3.0短视频+直播|vue3+vite2+vant3仿抖音界面|vue3.x小视频实例

Vue3.0短视频+直播|vue3+vite2+vant3仿抖音界面|vue3.x小视频实例

Vue3.0短视频+直播|vue3+vite2+vant3仿抖音界面|vue3.x小视频实例

Vue3.0短视频+直播|vue3+vite2+vant3仿抖音界面|vue3.x小视频实例

Vue3.0短视频+直播|vue3+vite2+vant3仿抖音界面|vue3.x小视频实例

Vue3.0短视频+直播|vue3+vite2+vant3仿抖音界面|vue3.x小视频实例

Vue3.0短视频+直播|vue3+vite2+vant3仿抖音界面|vue3.x小视频实例

Vue3.0短视频+直播|vue3+vite2+vant3仿抖音界面|vue3.x小视频实例

Vue3.0短视频+直播|vue3+vite2+vant3仿抖音界面|vue3.x小视频实例

Vue3.0短视频+直播|vue3+vite2+vant3仿抖音界面|vue3.x小视频实例

Vue3.0短视频+直播|vue3+vite2+vant3仿抖音界面|vue3.x小视频实例

Vue3.0短视频+直播|vue3+vite2+vant3仿抖音界面|vue3.x小视频实例

Vue3.0短视频+直播|vue3+vite2+vant3仿抖音界面|vue3.x小视频实例

Vue3.0短视频+直播|vue3+vite2+vant3仿抖音界面|vue3.x小视频实例

◆ vue3.x自定义顶部导航+标签栏

项目中所有顶部导航及底部tabbar均是使用vue3自定义组件来实现效果,支持自定义插槽内容。

Vue3.0短视频+直播|vue3+vite2+vant3仿抖音界面|vue3.x小视频实例

Vue3.0短视频+直播|vue3+vite2+vant3仿抖音界面|vue3.x小视频实例

Vue3.0短视频+直播|vue3+vite2+vant3仿抖音界面|vue3.x小视频实例

<navbar :back="false" bgcolor="transparent" transparent>
<template v-slot:title>
<div class="navbar__tab">
...
</div>
</template>
<template v-slot:right><div><i class="iconfont icon-search"></i></div></template>
</navbar> <tabbar
bgcolor="linear-gradient(to bottom, transparent, rgba(0,0,0,.6))"
color="rgba(255,255,255,.6)"
activeColor="#fff"
fixed
/>

◆ vue3.x全局弹出层组件

项目中所有的弹框应用场景均是之前开发的一款vue3自定义组件v3popup来实现功能。

Vue3.0短视频+直播|vue3+vite2+vant3仿抖音界面|vue3.x小视频实例

vue3版的自定义弹框组件,拥有20+种自定义参数配置,多种弹框类型及动画效果。

https://www.cnblogs.com/xiaoyan2017/p/14210820.html

◆ vite.config.js配置文件

一些简单的vite2项目配置,可进行一些常用环境及alias路径别名设置。

/**
* Vite2项目配置
*/ import vue from '@vitejs/plugin-vue' import path from 'path' /**
* @type {import('vite').UserConfig}
*/
export default {
plugins: [vue()], build: {
// 基本目录
// base: '/', /**
* 输出文件目录
* @default dist(默认)
*/
// outDir: 'target',
}, // 环境配置
server: {
// 自定义接口
port: 3000, // 是否自动浏览器打开
open: false, // 是否开启https
https: false, // 服务端渲染
ssr: false, // 代理配置
proxy: {
// ...
}
}, // 设置路径别名
alias: {
'@': path.resolve(__dirname, './src'),
'@components': path.resolve(__dirname, './src/components'),
'@views': path.resolve(__dirname, './src/views')
}
}

◆ 引入公共组件

让项目代码更加整洁,在plugins.js中配置一些公共组件,然后在main.js中引入即可。

/**
* 引入公共组件
*/ // 引入Vant3.x组件库
import Vant from 'vant'
import 'vant/lib/index.css' // 引入Vue3.x移动端弹层组件
import V3Popup from '@components/v3popup' import NavBar from '@components/navBar.vue'
import TabBar from '@components/tabBar.vue' import Utils from './utils'
import Storage from './storage' const Plugins = (app) => {
app.use(Vant)
app.use(V3Popup) // 注册公用组件
app.component('navbar', NavBar)
app.component('tabbar', TabBar) app.provide('utils', Utils)
app.provide('storage', Storage)
} export default Plugins

◆ vue3.x表单验证+60s倒计时

<!-- //注册表单模板 -->
<template>
<div>
<div class="vui__scrollview vui__scrollview-lgreg flex1">
<div class="nt__lgregPanel">
<div class="lgreg-header">
<div class="slogan">
<img class="logo" src="/static/logo.png" />
<p class="text ff-gg">Vue3.0-DouYin</p>
</div>
<div class="forms">
<form @submit.prevent="handleSubmit">
<div class="item flexbox flex_alignc">
<input class="iptxt flex1" type="text" v-model="formObj.tel" placeholder="请输入手机号" maxlength="11" />
</div>
<div class="item flexbox flex_alignc">
<input class="iptxt flex1" type="password" v-model="formObj.pwd" placeholder="请输入密码" />
</div>
<div class="item flexbox flex_alignc">
<input class="iptxt flex1" type="text" v-model="formObj.vcode" placeholder="验证码" />
<button class="btn-getcode" @click.prevent="handleVcode" :disabled="disabled">{{vcodeText}}</button>
</div>
<div class="item btns">
<button class="flex-c" type="submit"><i class="iconfont icon-go c-fff"></i></button>
</div>
<div class="item lgreg-lk">
<router-link class="navigator" to="/login">已有账号,去登录</router-link>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import { reactive, toRefs, inject, getCurrentInstance } from 'vue'
export default {
components: {},
setup() {
const { ctx } = getCurrentInstance() const v3popup = inject('v3popup') const utils = inject('utils') const formObj = reactive({})
const data = reactive({
vcodeText: '获取验证码',
disabled: false,
time: 0,
}) const VTMsg = (content) => {
v3popup({
content: `<div style='text-align:center;'><i class='iconfont icon-error'></i> ${content}</div>`,
popupStyle: 'background:#ffefe6;color:#fe2c55;',
position: 'top',
time: 2
})
} const handleSubmit = () => {
if(!formObj.tel){
VTMsg('手机号不能为空!')
}else if(!utils.checkTel(formObj.tel)){
VTMsg('手机号格式不正确!')
}else if(!formObj.pwd){
VTMsg('密码不能为空!')
}else if(!formObj.vcode){
VTMsg('验证码不能为空!')
}else{
// ...
}
} // 倒计时
const handleVcode = () => {
if(!formObj.tel) {
VTMsg('手机号不能为空!')
}else if(!utils.checkTel(formObj.tel)) {
VTMsg('手机号格式不正确!')
}else {
data.time = 60
data.disabled = true
countDown()
}
}
const countDown = () => {
if(data.time > 0) {
data.vcodeText = '获取验证码('+ data.time +')'
data.time--
setTimeout(countDown, 1000)
}else{
data.vcodeText = '获取验证码'
data.time = 0
data.disabled = false
}
} return {
formObj,
...toRefs(data),
handleSubmit,
handleVcode
}
}
}
</script>

◆ vue3.x实现小视频功能

小视频页面使用了有赞组件库中的swipe组件来实现滑动切换,开启lazy-render让滑动更加流畅。

Vue3.0短视频+直播|vue3+vite2+vant3仿抖音界面|vue3.x小视频实例

<div class="vui__swipeview">
<!-- ///滑动切换区 -->
<van-swipe ref="swipeHorizontalRef" :show-indicators="false" :loop="false" @change="handleSwipeHorizontal">
<van-swipe-item v-for="(item,index) in videoLs" :key="index">
<template v-if="item.category == 'nearby'">
<div class="swipe__nearLs">
...
</div>
</template>
<template v-if="item.category == 'recommend' || item.category == 'follow'">
<van-swipe vertical lazy-render :show-indicators="false" :loop="false" @change="handleSwipeVertical">
<van-swipe-item v-for="(item2, index2) in item.list" :key="index2">
<!-- ///视频模块 -->
<div class="swipe__video">
<video class="vdplayer" :id="'vd-'+index+'-'+index2" loop preload="auto"
:src="item2.src"
:poster="item2.poster"
webkit-playsinline="true"
x5-video-player-type="h5-page"
x5-video-player-fullscreen="true"
playsinline
@click="handleVideoClicked"
>
</video>
<span v-show="!isPlay" class="btn__play" @click="handleVideoClicked"><i class="iconfont icon-bofang"></i></span>
</div>
<!-- ///信息模块 -->
<div class="swipe__vdinfo flexbox flex-col">
<div class="flexbox flex-alignb">
<!-- ///底部信息栏 -->
<div class="swipe__footbar flex1">
<div v-if="item2.ads" class="item swipe__superlk ads" @click="handleOpenLink(item2)">
<i class="iconfont icon-copylink fs-28"></i>查看详情<i class="iconfont icon-arrR fs-24"></i>
</div>
<div v-if="item2.collectionLs&&item2.collectionLs.length>0" class="item swipe__superlk">
<i class="iconfont icon-copylink fs-24 mr-10"></i><div class="flex1">合集《小鬼当家》主演花絮</div><i class="iconfont icon-arrR fs-24"></i>
</div>
<div class="item uinfo flexbox flex-alignc">
<router-link to="/friend/uhome"><img class="avatar" :src="item2.avatar" /></router-link>
<router-link to="/friend/uhome"><em class="name">{{item2.author}}</em></router-link>
<button class="btn vui__btn vui__btn-primary" :class="item2.isFollow ? 'isfollow' : ''" @click="handleIsFollow(item.category, index2)">{{item2.isFollow ? '已关注' : '关注'}}</button>
</div>
<div class="item at">@{{item2.author}}</div>
<div v-if="item2.topic" class="item kw"><em v-for="(kw,idx) in item2.topic" :key="idx">#{{kw}}</em></div>
<div class="item desc">{{item2.desc}}</div>
</div>
<!-- ///右侧工具栏 -->
<div class="swipe__toolbar">
<div v-if="item2.goods&&item2.goods.length>0" class="item ball flexbox" @click="handleOpenGoods(item2.goods)"><i class="ico iconfont icon-cart"></i></div>
<div class="item" @click="handleIsLike(item.category, index2)"><i class="ico iconfont icon-like" :class="item2.isLike ? 'islike' : ''"></i><p class="num">{{item2.likeNum+(item2.isLike ? 1 : 0)}}</p></div>
<div class="item" @click="isShowReplyPopup=true"><i class="ico iconfont icon-liuyan"></i><p class="num">{{item2.replyNum}}</p></div>
<div class="item" @click="isShowSharePopup=true"><i class="ico iconfont icon-fenxiang"></i><p class="num">{{item2.shareNum}}</p></div>
</div>
</div>
</div>
</van-swipe-item>
</van-swipe>
</template>
</van-swipe-item>
</van-swipe>
<!-- ///底部进度条 -->
<div class="swipe__progress"><i class="bar" :style="{'width': vdProgress+'%'}"></i></div>
</div>
<script>
import { onMounted, onUnmounted, ref, reactive, toRefs, inject, nextTick } from 'vue' import CmtEditor from '@components/cmtEditor.vue' // ... export default {
components: {
CmtEditor,
},
setup() {
// 定时器
const vdTimer = ref(null)
const tapTimer = ref(null)
const swipeHorizontalRef = ref(null) const editorRef = ref(null) const v3popup = inject('v3popup') // ... // 垂直切换页面事件
const handleSwipeVertical = (index) => {
if(data.activeNav == 0) {
// 附近页
data.activeOneIdx = index
}else if(data.activeNav == 1) {
// 关注页
data.activeTwoIdx = index
// console.log('关注页索引:' + index)
}else if(data.activeNav == 2) {
// 推荐页
data.activeThreeIdx = index
// console.log('推荐页索引:' + index)
} vdTimer.value && clearInterval(vdTimer.value)
data.vdProgress = 0
data.isPlay = false
let video = getVideoContext()
if(!video) return
video.pause()
// 重新开始
video.currentTime = 0 data.activeSwipeIndex = index // 自动播放下一个
handlePlay()
} // 播放
const handlePlay = () => {
console.log('播放视频...') let video = getVideoContext()
if(!video) return
video.play()
data.isPlay = true // 设置进度条
vdTimer.value = setInterval(() => {
handleProgress()
}, 16)
} // 暂停
const handlePause = () => {
console.log('暂停视频...') let video = getVideoContext()
if(!video) return
video.pause()
data.isPlay = false
vdTimer.value && clearInterval(vdTimer.value)
} // 视频点击事件(判断单/双击)
const handleVideoClicked = () => {
console.log('触发视频点击事件...') tapTimer.value && clearTimeout(tapTimer.value)
data.clickNum++
tapTimer.value = setTimeout(() => {
if(data.clickNum >= 2) {
console.log('双击事件')
}else {
console.log('单击事件')
if(data.isPlay) {
handlePause()
}else {
handlePlay()
}
}
data.clickNum = 0
}, 300)
} // 播放进度条
const handleProgress = () => {
let video = getVideoContext()
if(!video) return
let curTime = video.currentTime.toFixed(1)
let duration = video.duration.toFixed(1)
data.vdProgress = parseInt((curTime / duration).toFixed(2) * 100)
} // ... // 打开链接
const handleOpenLink = (item) => {
// 监听路由地址栈
handlePopStateOpen() data.isShowLinkPopup = true
data.linkSrc = item.ads
data.linkTitle = item.adstitle ? item.adstitle : '网址链接'
} return {
...toRefs(data),
swipeHorizontalRef,
editorRef, handleTabNav,
handleSwipeHorizontal,
handleSwipeVertical,
handlePlay,
handlePause,
handleVideoClicked, // ...
}
}
}
</script>

Vue3.0短视频+直播|vue3+vite2+vant3仿抖音界面|vue3.x小视频实例

至于项目中的聊天模块就不详细介绍了,之前有分享过一篇vue3.0开发移动端聊天实例项目,感兴趣的可以去看看哈~~

https://www.cnblogs.com/xiaoyan2017/p/14250798.html

◆ vue3.x弹幕功能简单实现

直播页面在小视频页面功能基础上新增弹幕,滚动消息区、送礼物、充值弹窗等功能。

Vue3.0短视频+直播|vue3+vite2+vant3仿抖音界面|vue3.x小视频实例

Vue3.0短视频+直播|vue3+vite2+vant3仿抖音界面|vue3.x小视频实例

弹幕功能的简单实现,共有3条滚动路线。

const data = reactive({
// ... // 弹幕队列
idx: 2,
dmLs: [
...
],
// 正在执行的弹幕队列
dmActiveLs: []
}) onMounted(() => {
// ... // 装载弹幕
setInterval(() => {
starDanMu()
}, 1500)
}) const starDanMu = () => {
let query = null
if(!query) {
query = data.dmLs.shift()
}
if(query) {
query.row = data.idx
data.idx = (data.idx % 3 + 1)
data.dmActiveLs.push(query)
}
}
<div class="lv__wrap-danmu">
<div class="danmu__bx">
<div class="danmu__ls" v-for="item in dmActiveLs" :key="item.id" :data-row="item.row" @animationend="dmAnimationEnd">
<div class="item">
<img class="avatar" :src="item.avatar" />
<p class="name">{{item.name}}</p><p class="desc">{{item.desc}}</p>
</div>
</div>
</div>
</div>

OK,以上就是使用vue3.x+vite2开发仿抖音小视频/直播的一些分享,希望对大家有些帮助哈~~ ✍