基于vue3仿微信直播|vite2+vant3抖音短视频实例

xiaoyan2015 · · 3552 次点击 · 开始浏览    置顶
这是一个创建于 的主题,其中的信息可能已经有所发展或是发生改变。

## 项目介绍 > 前几天有给大家分享一个[vue3 web端聊天](https://studygolang.com/topics/13019)实例,今天分享的是最新开发的vue3仿抖音实战项目。 > [vue3Douyin仿抖音](https://juejin.cn/post/6924609446060490760/) 基于`vue3全家桶技术+有赞vant3组件库+vue3移动端弹框v3popup组件`搭建开发的一款`短视频/直播/聊天`实战案例。 ![](https://oscimg.oschina.net/oscnet/up-ce5decefbdfeb41eff8437233809c3b83c5.png) ## 使用技术 - 编码+技术:vscode | vue3.0.5+vue-router+vuex4 - 组件库:vant3.x (有赞移动端vue3组件库) - 弹层组件:v3popup(移动端vue3弹框组件) - 字体图标:阿里iconfont图标 - 导航条+Tab栏:自定义顶部导航/底部标签栏组件 - 构建工具:vite.js ![](https://oscimg.oschina.net/oscnet/up-e47c619526f7efdfd1e53cc43e1133bc973.gif) 使用vant3来实现短视频/直播页的滑动切换功能。 ![](https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/8f0998578c734e6a91560864c5eeff87~tplv-k3u1fbpfcp-watermark.image) ## 项目结构 ![](https://oscimg.oschina.net/oscnet/up-058a6cb943662a3868cb9d2c3384432cdf7.png) 整个项目采用vue3组合式语法来编码开发。 ![](https://oscimg.oschina.net/oscnet/up-9d503ef011ffa37b3d6ece5423221fa6b52.png) ![](https://oscimg.oschina.net/oscnet/up-4165ee3510b7983a68d1af4d0e34b574010.png) ![](https://oscimg.oschina.net/oscnet/up-0c3ffeb68ee6e7a5e1d81adafdb5a975c8c.png) ![](https://oscimg.oschina.net/oscnet/up-9aa093e30531020bc735cb732a04476728d.png) ![](https://oscimg.oschina.net/oscnet/up-cbdb80e82667240ca9d80eb4f56ea6efa91.png) ![](https://oscimg.oschina.net/oscnet/up-a4056c0a54d5c744a33ebf82c7f8f154628.png) ![](https://oscimg.oschina.net/oscnet/up-1af70903652e285a1fc73c9daca5247a0ca.png) ![](https://oscimg.oschina.net/oscnet/up-ddd470047f9fa167db63db90c36e9c92118.png) ![](https://oscimg.oschina.net/oscnet/up-b5a10b75fbd3aa804500483de90946fc350.png) ## 自定义弹框v3popup 基于vue3.0开发的一款移动端对话框组件,支持多种弹窗类型及动画效果。 ![](https://oscimg.oschina.net/oscnet/up-e153a4295576b63bcd477c27b6e61417a57.png) 在整个项目中都有应用到这个插件。支持函数式/标签式调用方式。 ![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/8c30ec5c0b574262b053ad2914d8d772~tplv-k3u1fbpfcp-watermark.image) [vue3.x开发手机端自定义弹框组件](https://www.cnblogs.com/xiaoyan2017/p/14210820.html) ## 项目配置 vite.js构建功能创建的项目,会有一个vite.config.js配置文件。 ``` /** * vite.config.js项目配置 */ import vue from '@vitejs/plugin-vue' import path from 'path' /** * @type {import('vite').UserConfig} */ export default { plugins: [vue()], build: { // 基本目录 // base: '/', /** * 输出文件目录 * <a href="/user/default" title="@default">@default</a> dist(默认) */ // outDir: 'target', }, // 环境配置 server: { // 自定义接口 port: 3000, // 是否自动浏览器打开 open: false, // 是否开启https https: false, // 代理配置 proxy: { // ... } }, // 设置路径别名 alias: { '@': path.resolve(__dirname, './src'), '@components': path.resolve(__dirname, './src/components'), '@views': path.resolve(__dirname, './src/views') } } ``` ## vue3抽离公共组件 新建一个plugins.js来引入一些常用的公共组件。 ``` /** * vue3引入公共组件 */ // 引入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) } ``` ## vue3实现小视频/直播功能 大家可以看到小视频和直播模板有些地方的功能是通用的。都是使用swipe来实现滑动效果。 ![](https://oscimg.oschina.net/oscnet/up-f1317e2ca89c1d7ab42b07739491f9a9b90.png) 整体分为顶部+视频区+底部三大部分。 ``` <template> <div class="bg-161823"> <!-- >>顶部NavBar --> <navbar :back="false" bgcolor="transparent" transparent> <template v-slot:title> ... </template> <template v-slot:right><div><i class="iconfont icon-search"></i></div></template> </navbar> <!-- >>主面板 --> <div class="vui__scrollview flex1"> <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> </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> </div> <!-- >>底部TabBar --> <tabbar bgcolor="linear-gradient(to bottom, transparent, rgba(0,0,0,.6))" color="rgba(255,255,255,.6)" activeColor="#fff" fixed /> <!-- ……商品模板 --> <v3-popup v-model="isShowGoodsPopup" position="bottom" round xclose title="热销商品" @end="handlePopStateClose" opacity=".2"> <div v-if="goodsLs" class="wrap_goodsList"> ... </div> </v3-popup> <!-- ……评论列表模板 --> <v3-popup v-model="isShowReplyPopup" position="bottom" round xclose opacity=".2"> <div class="nt__commentWrap"> <!-- 评论列表 --> ... </div> </v3-popup> <!-- ……评论编辑器模板 --> <v3-popup v-model="isShowReplyEditor" position="bottom" opacity=".2"> <div class="vui__footTool nt__commentWrap"> ... </div> </v3-popup> <!-- ……分享模板 --> <v3-popup v-model="isShowSharePopup" anim="footer" type="actionsheet" round xclose opacity=".2" title="<div style='text-align:left;'>分享至</div>" :btns="[ {text: '取消', style: 'color:#999;', click: () => isShowSharePopup=false}, ]" > ... </v3-popup> </div> </template> <script> /** * #Desc Vue3.0实现小视频功能 * #Time andy by 2021-02 * #About Q:282310962 wx:xy190310 */ import { onMounted, onUnmounted, ref, reactive, toRefs, inject, nextTick } from 'vue' import CmtEditor from '@components/cmtEditor.vue' import videoJSON from '@/mock/videolist.js' import emojJSON from '@/mock/cmt-emoj.js' 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 data = reactive({ // ... }) onMounted(() => { swipeHorizontalRef.value.swipeTo(data.activeNav, {immediate: true}) // ... }) // ... // 垂直切换页面事件 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) } // ... return { ...toRefs(data), swipeHorizontalRef, editorRef, // ... } } } </script> ``` 另外小视频页底部有一个迷你播放进度条,实时展示当前播放进度。 ![](https://oscimg.oschina.net/oscnet/up-f162fad257878603503057ab36da3d4d8c0.png) ok,使用vue3+vant3开发小视频/直播项目就暂时分享到这里。 ![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/035c8d7b00164d8089e6ae790ed48f3f~tplv-k3u1fbpfcp-zoom-1.image)

有疑问加站长微信联系(非本文作者)

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

3552 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传