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

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

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

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

一、运用技术

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

二、项目目录结构

◆ 效果预览

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

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


    
        
    
    

◆ vue3.x全局弹出层组件

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

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倒计时



    

Vue3.0-DouYin

已有账号,去登录

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: `
${content}
`, 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 } } }

◆ vue3.x实现小视频功能

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

...
查看详情
0" class="item swipe__superlk">
合集《小鬼当家》主演花絮
{{item2.author}}
@{{item2.author}}
#{{kw}}
{{item2.desc}}
0" class="item ball flexbox" @click="handleOpenGoods(item2.goods)">

{{item2.likeNum+(item2.isLike ? 1 : 0)}}

{{item2.replyNum}}

{{item2.shareNum}}


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,

            // ...
        }
    }
}

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

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

◆ 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)
    }
}

{{item.name}}

{{item.desc}}

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

最后附上一个vue3网页版聊天项目

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