x***@126.com
x***@126.com
  • 发布:2021-09-26 23:40
  • 更新:2024-03-27 09:15
  • 阅读:3429

nvue+uniapp模仿抖音APP实例|uni-app直播/短视频

分类:uni-app

之前有给大家分享一个electron-webosx仿MAC桌面管理系统。今天分享的是全端uniapp小视频/直播实例项目。

uniapp-ttLive短视频 一款基于uni-app+nvue+uview-ui等技术开发的多功能跨端直播+短视频项目。流畅的上下滑动体验、支持全景式悬浮沉浸效果。可暂停/播放小视频、直播送礼物、聊天互动等功能。

vue3.x+electron13+vite2模仿macui桌面管理框架

img

使用技术

  • 编码器/技术:HbuilderX3.1.21+Uniapp+Nvue+Vuex+Uapopup
  • UI组件库:uView-ui / uni-ui
  • 矢量图标库:iconfont字体图标
  • 弹窗组件:UApopup 基于uni-app封装跨端弹窗组件
  • 自定义导航条+底部菜单栏
  • 编译支持:H5+小程序+APP端

img

基于 HbuilderX3.1.21 编码器开发,搭配nvue原生页面解决video层级过高问题,自定义 ua-navbar ua-tabbar ua-popup 组件全面支持Nvue页面。搭配uview-ui和uni-ui组件库。可编译至h5+小程序+APP端。

img

项目结构目录

img

img

img

img

img

img

img

img

img

img

img

img

img

img

img

img

main.js配置

import Vue from 'vue'  
import App from './App'  

import uView from 'uview-ui'  
Vue.use(uView)  

// 引入状态管理  
import Store from './store'  
Vue.prototype.$store = Store  

const app = new Vue({  
    ...App  
})  
app.$mount()  

全局获取状态栏高度

<script>  
    export default {  
        globalData: {  
            // 全局设置状态栏和导航栏高度  
            statusBarH: 0,  
            customBarH: 0,  
        },  
        onLaunch: function() {  
            console.log('App Launch')  

            let token = uni.getStorageSync('token')  
            if(!token) {  
                uni.navigateTo({  
                    url: '/pages/auth/login'  
                })  
            }  

            uni.getSystemInfo({  
                success: (e) => {  
                    // 获取手机状态栏高度  
                    let statusBar = e.statusBarHeight  
                    let customBar  

                    // #ifndef MP  
                    customBar = statusBar + (e.platform == 'android' ? 50 : 45)  
                    // #endif  

                    // #ifdef MP-WEIXIN  
                    // 获取胶囊按钮的布局位置信息  
                    let menu = wx.getMenuButtonBoundingClientRect()  
                    // 导航栏高度 = 胶囊下距离 + 胶囊上距离 - 状态栏高度  
                    customBar = menu.bottom + menu.top - statusBar  
                    // #endif  

                    // #ifdef MP-ALIPAY  
                    customBar = statusBar + e.titleBarHeight  
                    // #endif  

                    // 兼容nvue写法(H5/小程序/APP/APP-Nvue)  
                    this.globalData.statusBarH = statusBar  
                    this.globalData.customBarH = customBar  
                }  
            })  
        },  
        onShow: function() {  
            console.log('App Show')  
        },  
        onHide: function() {  
            console.log('App Hide')  
        }  
    }  
</script>  

uni-app全端自定义组件

img

img

项目中用到的顶部导航栏、底部菜单栏及弹窗均是自定义组件来实现功能。

<ua-popup v-model="isVisibleConfirm" shadeClose="false" title="标题" xclose z-index="1001"  
    content="<div style='color:#ff557f;padding:20px 40px;'>预测未来的最好办法是自己亲手创造未来!</div>"  
    :btns="[  
        {text: '取消', click: handleCancel},  
        {text: '确定', style: 'color:#00aa00;', click: handleOk},  
    ]"  
/>  
<script>  
export default {  
    methods: {  
        handleOk() {  
            let $ua = this.$refs.uapopup  
            $ua.open({  
                content: '人生漫漫,且行且珍惜',  
                customStyle: {'background-color': 'rgba(170, 0, 127, 0.6)', 'color': '#fff'},  
                time: 3,  
                onClose() {  
                    $ua.open({  
                        type: 'android',  
                        content: '<div style="color:#aa007f">一切都将一去杳然,任何人都无法将其捕获。</div>',  
                        customStyle: {'width': '210px'},  
                        btns: [  
                            {  
                                text: '关闭',  
                                click() {  
                                    $ua.close()  
                                }  
                            },  
                            {  
                                text: '确定',  
                                style: 'color:#00aa00;',  
                                click() {  
                                    // ...  
                                }  
                            }  
                        ]  
                    })  
                }  
            })  
        }  
    }  
}  
</script>

uniapp自定义组件之导航栏+菜单栏

uniapp全端弹窗插件|uni-app模态弹框

uniapp直播/短视频

项目中短视频页面,整体分为顶部导航栏、底部菜单栏、中间视频区域。

<view v-if="currentTab == 2" class="ua__tabcnt-recommend">  
    <swiper class="ua__vdplayer-swiper flex1" :current="currentVideo" vertical @change="handleSwipeVertical">  
        <swiper-item v-for="(item, index) in videoList" :key="index">  
            <!-- 视频模块 -->  
            <view class="ua__vdplayer-video flex1">  
                <video class="vdplayer" :id="'vdplayer' + index" :ref="'vdplayer' + index"   
                    :src="item.src"  
                    :controls="false" :loop="true" :show-center-play-btn="false" object-fit="fill"  
                    :autoplay="index == currentVideo"  
                    @play="isPlaying=true" @timeupdate="handleTimeUpdate"  
                    :style="{'width': winWidth, 'height': winHeight}"  
                >  
                </video>  
                <view class="ua__vdplayer-playwrap" @click="handleVideoClicked"><view v-if="!isPlaying" class="ua__vdplayer-playbtn"><text class="iconfont">{{`\ue607`}}</text></view></view>  
            </view>  
            <!-- 信息模块 -->  
            <view class="ua__vdplayer-info flexbox flex-col">  
                <view class="flexbox flex-row flex-alignb">  
                    <!-- //左侧信息 -->  
                    <view class="vdinfo__left flex1">  
                        <view class="ltitem uavatar flexbox flex-row">  
                            <navigator url="#" class="flexbox flex-alignc flex-row"><image class="uimg" :src="item.avatar" /><text class="uname">{{item.author}}</text></navigator>  
                            <view class="flexbox btn" :class="{'actived': item.isFollow}" @click="handleFollow(index)"><text class="btn-text">{{item.isFollow ? '已关注' : '关注'}}</text></view>  
                        </view>  
                        <view v-if="item.topic" class="ltitem flexbox flex-row">  
                            <view class="kw" v-for="(kw, index2) in item.topic" :key="index2"><text class="lbl">#{{kw}}</text></view>  
                        </view>  
                        <view class="ltitem"><text class="desc">{{item.desc}}</text></view>  
                    </view>  
                    <!-- //右侧按钮 -->  
                    <view class="vdinfo__right flexbox flex-col">  
                        <view class="rtitem ball" v-if="item.goods&&item.goods.length > 0" @click="handleShowGoodsPopup(item.goods)"><text class="icon iconfont">{{`\ue734`}}</text></view>  
                        <view class="rtitem" :class="{'isliked': item.isLike}" @click="handleLiked(index)"><text class="icon iconfont">{{`\ue635`}}</text><text class="num">{{item.likeNum+(item.isLike ? 1 : 0)}}</text></view>  
                        <view class="rtitem" @click="showReplyPopup = true"><text class="icon iconfont">{{`\ue632`}}</text><text class="num">{{item.replyNum}}</text></view>  
                        <view class="rtitem" @click="showSharePopup = true"><text class="icon iconfont">{{`\ue63b`}}</text><text class="num">{{item.shareNum}}</text></view>  
                    </view>  
                </view>  
            </view>  
        </swiper-item>  
    </swiper>  
    <!-- 底部播放进度条 -->  
    <view class="ua__vdplayer-progress"><view class="bar" :style="{'width': progressBar+'px'}"></view></view>  
</view>
<script>  
    const app = getApp()  
    import videoJSON from '@/mock/videolist.js'  

    export default {  
        data() {  
            return {  
                // 导航栏高度  
                customBarHeight: app.globalData.customBarH,  
                navbarBgcolor: '#21252b',  
                tabbarBgcolor: '#21252b',  

                tabNavLs: [  
                    {label: '附近动态', badge: 5, lists: []},  
                    {label: '关注', lists: []},  
                    {label: '推荐', dot: true, lists: []},  
                ],  
                // 当前选项卡  
                currentTab: 0,  

                // 当前视频索引  
                currentVideo: 0,  
                // 视频数据  
                videoList: videoJSON,  
                // 视频是否播放中  
                isPlaying: false,  
                // 点击次数  
                clickNum: 0,  
                // 视频播放进度条  
                progressBar: 0,  
                clickTimer: null,  

                // 屏幕宽高  
                winWidth: '',  
                winHeight: '',  

                popupGoodsList: [],  
                showGoodsPopup: false,  
                showReplyPopup: false,  
                showSharePopup: false,  
            }  
        },  
        watch: {  
            currentTab(val) {  
                this.changeTabPanel(val)  
            }  
        },  
        computed:{  
            customBarMargin() {  
                return `margin-top: ${this.customBarHeight}px`  
            }  
        },  
        created() {  
            // 引入iconfont字体  
            // #ifdef APP-NVUE  
            const domModule = weex.requireModule('dom')  
            domModule.addRule('fontFace', {  
                fontFamily: "nvueIcon",  
                'src': "url('/static/fonts/iconfont.ttf')"  
            });  
            // #endif  

            let wW = uni.getSystemInfoSync().windowWidth  
            let wH = uni.getSystemInfoSync().windowHeight  
            this.winWidth = `${wW}px`  
            this.winHeight = `${wH}px`  
        },  
        methods: {  

            // 长按动态  
            handleDynamicMenu(e) {  
                let points  
                // #ifndef APP-NVUE  
                points = [e.touches[0].clientX, e.touches[0].clientY]  
                // #endif  
                // #ifdef APP-NVUE  
                points = [e.touches[0].screenX, e.touches[0].screenY]  
                // #endif  

                this.$refs.uapopup.open({  
                    type: 'contextmenu',  
                    follow: points,  
                    btns: [  
                        {text: '不感兴趣'},  
                        {text: '复制'},  
                        {  
                            text: '举报',  
                            style: 'color:#f00;',  
                            click: () => {  
                                this.$refs.uapopup.close()  
                            }  
                        },  
                    ],  
                })  
            },  

            /* ++++++++++ { 视频播放模块 } ++++++++++ */  
            getVideoCtx() {  
                // return this.$refs['vdplayer' + this.currentVideo][0]  
                return uni.createVideoContext('vdplayer'+ this.currentVideo, this)  
            },  

            // 垂直滑动视频  
            handleSwipeVertical(e) {  
                let index = e.detail.current  
                this.progressBar = 0  
                this.isPlaying = false  
                let video = this.getVideoCtx()  
                if(!video) return  
                video.pause()  
                // 重新开始  
                video.seek(0)  

                this.currentVideo = index  

                // 自动播放  
                this.handlePlay()  
            },  

            handlePlay() {  
                let video = this.getVideoCtx()  
                if(!video) return  
                video.play()  
                this.isPlaying = true  
            },  

            handlePause() {  
                let video = this.getVideoCtx()  
                if(!video) return  
                video.pause()  
                this.isPlaying = false  
            },  

            // 点击视频(单击/双击)  
            handleVideoClicked() {  
                this.clickTimer && clearTimeout(this.clickTimer)  
                this.clickNum++  
                this.clickTimer = setTimeout(() => {  
                    if(this.clickNum >= 2) {  
                        console.log('你双击了')  
                    }else {  
                        console.log('你单击了')  
                        if(this.isPlaying) {  
                            this.handlePause()  
                        }else {  
                            this.handlePlay()  
                        }  
                    }  
                    this.clickNum = 0  
                }, 250)  
            },  

            ...  
        }  
    }  
</script>

okey,基于uni-app开发原生短视频/直播项目就分享到这里。

链接:https://juejin.cn/post/7010195797174124557/
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

0 关注 分享

要回复文章请先登录注册

x***@126.com

x***@126.com (作者)

回复 龙虾网络 :
感谢支持。
2024-03-27 09:15
龙虾网络

龙虾网络

厉害
2024-03-26 08:54
x***@126.com

x***@126.com (作者)

![img](https://img2023.cnblogs.com/blog/1289798/202401/1289798-20240101095720543-302785932.png)
[https://www.cnblogs.com/xiaoyan2017/p/17938517](https://www.cnblogs.com/xiaoyan2017/p/17938517)
2024-03-25 22:19