基于uniapp+vue3+vk-uview仿抖音微信直播商城应用|uniapp+vue3短视频
【摘要】 前段时间有分享一篇electron27+react18跨端仿制mateOs桌面系统项目,今天再来分享一款uniapp+vue3跨端仿制抖音短视频+直播商城应用。https://bbs.huaweicloud.com/blogs/416211uniapp-dylive:全新基于uniapp+vue3+pinia+vk-uview等技术跨端仿制抖音/微信直播带货商城项目。支持沉浸式全屏上下滑动短...
前段时间有分享一篇electron27+react18跨端仿制mateOs桌面系统项目,今天再来分享一款uniapp+vue3跨端仿制抖音短视频+直播商城应用。
https://bbs.huaweicloud.com/blogs/416211
uniapp-dylive:全新基于uniapp+vue3+pinia+vk-uview等技术跨端仿制抖音/微信直播带货商城项目。支持沉浸式全屏上下滑动短视频直播,Nvue多视频层级覆盖,支持编译到兼容H5+小程序+App端。
使用技术
- 编辑器:HbuilderX 3.98
- 框架技术:Uniapp+Vue3+Vite4+Nvue+Pinia
- UI组件库:uv-ui+vk-uview
- 弹框组件:uaPopup(uniapp封装多端弹框组件)
- 自定义组件:uaNavbar+uaTabbar组件
- 本地缓存:pinia-plugin-unistorage
- 编译支持:H5+小程序+APP端
项目目录结构
整个项目采用vue3 setup语法开发。
main.js配置
/**
* 入口配置
*/
import { createSSRApp } from 'vue'
import App from './App'
// 引入Pinia状态管理
import Pinia from '@/store'
// 引入vk-uview-ui组件库
import VKuview from '@/uni_modules/vk-uview-ui'
export function createApp() {
const app = createSSRApp(App)
app.use(Pinia)
app.use(VKuview)
return {
app,
Pinia
}
}
App.vue模板配置
<script>
export default {
globalData: {
// 全局设置状态栏和导航栏高度
statusBarH: 0,
customBarH: 0,
screenWidth: 0,
screenHeight: 0,
menuBar: null
},
onLaunch: function() {
console.log('App Launch')
// 隐藏系统tabbar
uni.hideTabBar()
this.appInit()
},
onShow: function() {
console.log('App Show')
},
onHide: function() {
console.log('App Hide')
},
onPageNotFound: function() {
console.log('Page Not Found', e.path)
uni.redirectTo({
url: '/pages/index/index'
})
},
methods: {
appInit: function() {
uni.getSystemInfo({
success: (e) => {
// 获取手机状态栏信息
let statusBar = e.statusBarHeight || 0
let customBar
let menuBar
// #ifndef MP
customBar = statusBar + (e.osName === 'android' ? 50 : 45)
// #endif
// #ifdef MP-WEIXIN
// 获取微信小程序胶囊按钮信息
let menu = wx.getMenuButtonBoundingClientRect()
// 导航栏高度 = 胶囊下距离 + 胶囊上距离 - 状态栏高度
customBar = menu.bottom + menu.top - statusBar
menuBar = menu
// #endif
// // #ifdef MP-ALIPAY
customBar = statusBar + e.titleBarHeight
// #endif
// 兼容nvue写法(H5/小程序/APP/APP-Nvue)
this.globalData.statusBarH = statusBar
this.globalData.customBarH = customBar
this.globalData.screenWidth = e.screenWidth
this.globalData.screenHeight = e.screenHeight
this.globalData.menuBar = menuBar
}
})
}
}
}
</script>
<style>
/* #ifndef APP-NVUE */
@import 'static/fonts/iconfont.css';
/* #endif */
.nvueicon {font-family: nvueicon;}
</style>
<style lang="scss">
// 引入vk-uview-ui基础样式
@import 'uni_modules/vk-uview-ui/index.scss';
@import 'styles/reset.scss';
@import 'styles/layout.scss';
</style>
uniapp+vue3短视频模板
<ua-layout>
<view class="ua__swipervideo flex1">
<swiper
class="ua__swipervideo-wrap flex1"
:current="currentVideo"
vertical
:circular="true"
:duration="200"
@change="handleChange"
@transition="handleTransition"
>
<swiper-item v-for="(item, index) in videoList" :key="index">
<video
class="ua__swipervideo-player flex1"
:id="'uplayer' + index"
:src="item.src"
:danmu-list="item.danmu"
:enable-danmu="true"
:controls="false"
:loop="true"
:autoplay="index == currentVideo"
:show-center-play-btn="false"
object-fit="contain"
@click="handleClickVideo"
@play="isPlaying=true"
@timeupdate="handleTimeUpdate"
:style="{'width': `${winWidth}px`, 'height': `${winHeight}px`}"
>
</video>
<!-- 浮层模块 -->
<view class="ulive__video-float__info flexbox flex-col">
<view class="flexbox flex-row flex-alignb">
<!-- 左侧 -->
<view class="vdinfo__left flex1 flexbox flex-col">
<view class="ltrow danmu flexbox" @click="handleOpenDanmu"><text class="danmu-txt">弹</text><uv-icon class="ico" name="edit-pen" color="#fff" size="14" /></view>
<view class="ltrow"><text class="ait">@{{item.author}}</text></view>
<view class="ltrow"><text class="desc">{{item.desc}}</text></view>
</view>
<!-- 右侧操作栏 -->
<view class="vdinfo__right flexbox flex-col">
<view class="rtbtn avatar flexbox flex-col">
<view class="ubox"><image class="uimg" :src="item.avatar" mode="aspectFill" /></view>
<view class="btn flexbox" :class="{'active': item.isFollow}" @click="handleFollow(index)"><uv-icon :name="item.isFollow ? 'checkmark' : 'plus'" :color="item.isFollow ? '#ff007f' : '#fff'" size="11" /></view>
</view>
<view class="rtbtn flexbox flex-col" @click="handleLiked(index)"><uv-icon name="heart-fill" :color="item.isLike ? '#ff007f' : '#fff'" size="40" /><text class="num">{{item.likeNum+(item.isLike ? 1 : 0)}}</text></view>
<view class="rtbtn flexbox flex-col" @click="handleOpenComment(index)"><uv-icon name="chat-fill" color="#fff" size="40" /><text class="num">{{item.replyNum}}</text></view>
<view class="rtbtn flexbox flex-col"><uv-icon name="star-fill" color="#fff" size="40" /><text class="num">{{item.starNum}}</text></view>
<view class="rtbtn flexbox flex-col" @click="handleOpenShare(index)"><uv-icon name="share-fill" color="#fff" size="40" /><text class="num">{{item.shareNum}}</text></view>
</view>
</view>
</view>
</swiper-item>
</swiper>
<!-- 固定tabs(脱离滑动区) -->
<view class="ulive__video-header__tabs" :style="{'margin-top': `${menuBarT}px`}">
<uv-tabs :current="tabsCurrent" :list="tabsList" />
</view>
<!-- 播放暂停按钮 -->
<view v-if="!isPlaying" class="ua__swipervideo-playbtn" :style="{'left': `${winWidth/2}px`, 'top': `${winHeight/2}px`}" @click="handleClickVideo">
<text class="ua__swipervideo-playico welive-icon welive-icon-play nvueicon"></text>
</view>
<!-- 播放mini进度条 -->
<view class="ua__swipervideo-progress" :style="{'width': `${winWidth}px`}"><view class="ua__swipervideo-progressbar" :style="{'width': `${progressBar}px`}"></view></view>
</view>
<template #footer>
<ua-tabbar bgcolor="transparent" color="rgba(255,255,255,.7)" :border="false" :dock="false" transparent z-index="1000" />
</template>
</ua-layout>
<script setup>
/**
** uniapp+vue3短视频模块 Q:282310962
*/
import { ref, computed, getCurrentInstance } from 'vue'
import { onShow, onHide } from '@dcloudio/uni-app'
import { getRandomColor } from '@/utils'
// ...
const { globalData } = getApp()
const menuBarT = ref(globalData.menu?.top || globalData.statusBarH)
const winWidth = ref(globalData.screenWidth)
const winHeight = ref(globalData.screenHeight)
const tabsList = ref([
{ name: '推荐', count: 5 },
{ name: '关注' },
{ name: '同城' }
])
const tabsCurrent = ref(0)
// 视频参数
const currentVideo = ref(0)
const isPlaying = ref(false)
const clickNum = ref(0)
const clickTimer = ref(null)
const progressBar = ref(0)
// 视频源
const videoList = ref(videoJson)
const danmuEditor = ref('')
const isVisibleDanmu = ref(false)
const commentRef = ref(null)
const shareRef = ref(null)
// ...
/**
* ====================== 视频播放模块 ======================
*/
// 创建并返回 video 上下文 videoContext 对象
const getVideoContext = () => {
// return uni.createVideoContext(`uplayer${currentVideo.value}`, this)
return uni.createVideoContext(`uplayer${currentVideo.value}`, getCurrentInstance())
}
// 垂直滑动视频,滑动改变时会触发 change 事件
const handleChange = (e) => {
const index = e.detail.current
progressBar.value = 0
handleReset()
currentVideo.value = index
// 播放
handlePlay()
}
// 播放
const handlePlay = () => {
console.log('video play')
let video = getVideoContext()
if(!video) return
video.play()
isPlaying.value = true
}
// 暂停
const handlePause = () => {
console.log('video pause')
let video = getVideoContext()
if(!video) return
video.pause()
isPlaying.value = false
}
// 重置播放
const handleReset = () => {
console.log('video reset')
let video = getVideoContext()
if(!video) return
video.pause()
video.seek(0)
video.stop()
isPlaying.value = false
}
// 监听播放进度条
const handleTimeUpdate = (e) => {
let { currentTime, duration } = e.detail
progressBar.value = parseInt((currentTime / duration).toFixed(2) * parseInt(winWidth.value))
}
// 点击视频(监听单双击)
const handleClickVideo = () => {
console.log('video click')
clearTimeout(clickTimer.value)
clickNum.value++
clickTimer.value = setTimeout(() => {
if(clickNum.value >= 2) {
console.log('double click')
}else {
if(isPlaying.value) {
handlePause()
}else {
handlePlay()
}
}
clickNum.value = 0
}, 200)
}
/**
* ====================== 其它功能模块 ======================
*/
// 打开弹幕弹框
const handleOpenDanmu = () => {
isVisibleDanmu.value = true
}
// 关闭弹幕弹框
const handleCloseDanmu = () => {
uni.hideKeyboard()
isVisibleDanmu.value = false
danmuEditor.value = ''
}
// 发送弹幕
const handleSendDanmu = () => {
let video = getVideoContext()
if(!video) return
video.sendDanmu({
text: danmuEditor.value,
color: getRandomColor()
})
handleCloseDanmu()
}
// 打开评论框
const handleOpenComment = (index) => {
commentRef.value.open()
}
// ...
</script>
OK,以上就是uni-app+vue3开发直播商城的一些分享知识。
来源: segmentfault.com,作者:xiaoyan2017,版权归原作者所有,如需转载,请联系作者。
【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
评论(0)