乐趣区

关于vue-router:基于vite2vue3xvant3小视频直播聊天实战vue30仿抖音短视频

我的项目介绍

Vue3DouYin 基于 vite2+vue3.0+vant3+v3popup 等技术开发的一款 挪动端仿抖音 / 快手 App 界面短视频 实例我的项目。实现了 滑动切换视频、暂停 / 进度条展现、点赞 / 评论 / 聊天、弹幕 / 送礼物 / 红包 等性能。

技术栈

  • 编码 + 技术:vscode + vite2/vue3.0/vue-router/vuex4
  • UI 组件库:vant3 (有赞挪动端 vue3 组件库)
  • 弹层组件:v3popup(挪动端 vue3 弹框组件)
  • 字体图标:阿里 iconfont 图标
  • 导航条 + 底部栏:自定义顶部 navbar/tabbar 标签栏组件

我的项目目录构造

vue3 自定义手机端弹框组件

v3popup 一款应用 vue3 开发的 mobile 端自定义弹框组件。完满的融入到我的项目中各个弹窗场景。

因为之前写过一篇这方面的分享,大家感兴趣的话能够去看下。
vue3.0 系列之自定义 mobile 版弹出层组件 |vue3 挪动端弹框

vite2 我的项目配置

/**
 * 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')
  }
}

vue3 主入口 main.js 配置

引入一些路由 / 状态治理,公共组件及款式。

/**
 * vue3.0 主页面配置
 */

import {createApp} from 'vue'
import App from './App.vue'

// 引入 Router 及 Vuex
import router from './router'
import store from './store'

// 引入专用组件
import Plugins from './plugins'

// 引入 Js
import '@/assets/js/fontSize'

// 引入专用款式
import '@/assets/fonts/iconfont.css'
import '@/assets/css/reset.css'
import '@/assets/css/layout.css'

const app = createApp(App)

app.use(router)
app.use(store)
app.use(Plugins)

app.mount('#app')

vue3 小视频 / 直播性能

应用有赞 vue3 组件库中的 swipe 组件实现小视频高低滑动轮播成果。

<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">![](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>
/**
 * @Desc     vue3.0+vant3 小视频 / 直播
 * @Time     andy by 2021-02
 * @About    Q:282310962  wx:xy190310
 */
import {onMounted, onUnmounted, ref, reactive, toRefs, inject, nextTick} from 'vue'

// ...

export default {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)
        }

        return {...toRefs(data),

            // ...
        }
    }
}
</script>

直播页面送礼物 / 充值等弹窗都是应用 v3popup 组件实现。

<!-- ……送礼物模板 -->
<v3-popup v-model="isShowGiftPopup" position="bottom" round popupStyle="background:#36384a;">
    <div class="wrap_giftList">
        <div class="gt__hdtit flex-c">
            <i class="back iconfont icon-close" @click="isShowGiftPopup=false"></i>
            <div class="flex1"> 赠送礼物 </div>
            <div class="num" @click="isShowRechargePopup=true"><i class="iconfont icon-douzi fs-24"></i> 0 <i class="iconfont icon-arrR fs-24"></i></div>
        </div>
        <div class="gt__swipe">
            <div class="gtitem" :class="giftCur == index ?'on':''" v-for="(item,index) in giftLs" :key="index" @click="handleGiftClicked(item, index)">
                <div class="inner flex-c flex-col">
                    ![](item.giftPic)
                    <p class="gtlbl">{{item.giftLabel}}</p>
                    <p class="gtnum"><i class="iconfont icon-douzi"></i> {{item.giftCoins}}</p>
                </div>
            </div>
        </div>
    </div>
</v3-popup>

<!-- ……充值模板(微信豆)-->
<v3-popup v-model="isShowRechargePopup" position="bottom" round popupStyle="background:#36384a;" opacity="0">
    <div class="wrap_giftList">
        <div class="gt__hdtit flex-c">
            <i class="back iconfont icon-arrD" @click="isShowRechargePopup=false"></i>
            <div class="flex1"> 抉择充值金额 </div>
            <div class="num"><i class="iconfont icon-douzi fs-24"></i> 0</div>
        </div>
        <div class="gt__swipe gt__recharge">
            <div class="gtitem" :class="rechargeIdx == index ?'cur':''" v-for="(item,index) in rechargeLs" :key="index" @click="handleRecharge(index)">
                <div class="inner flex-c flex-col">
                    <p class="gtcoins"><i class="iconfont icon-douzi"></i> {{item.gtcoins}}</p>
                    <p class="gtmoney"> 售价 {{item.gtmoney}} 元 </p>
                </div>
            </div>
            <div class="pad10"><button class="vui__btn vui__btn-primary" style="border-radius:.1rem;height:40px;" @click="isShowSubmitRecharge=true"> 确认领取(¥{{rechargeLs[rechargeIdx].gtmoney}})</button></div>
        </div>
    </div>
</v3-popup>

ok,基于 vue3+vite2 开发短视频 / 直播实例就临时分享这么多,感激大家的反对!????

最初附上一个 Vue3+ElementPlus 桌面 web 端聊天实例
vue3.x 仿造微信 / 微博 web 版聊天室

退出移动版