jiuyiUniapp/jiuyi2/components/index/indexVideo.vue

549 lines
12 KiB
Vue
Raw Normal View History

2024-12-18 15:46:27 +08:00
<script setup>
/**
* 首页视频组件
* @property {Object} item 视频数据对象
* @property {Number} index 当前视频列表索引
* @property {Number} current 当前预览索引
*/
import {
onMounted,
ref,
reactive,
getCurrentInstance,
watch,
defineEmits,
computed,
nextTick
} from 'vue';
const {
proxy
} = getCurrentInstance()
// 顶部状态栏
import statusBar from '@/components/header/statusBar.vue'
// 工具库
import util from '@/common/js/util';
//
import api from '@/api/index.js';
// #ifdef APP-NVUE
const dom = uni.requireNativePlugin('dom')
// #endif
const props = defineProps({
// 当前视频对象
item: {
type: Object,
},
// 列表中的视频下标
index: {
type: Number,
},
// 当前列表的index
current: {
type: Number,
},
// 当前tab的index
tabIndex: {
type: Number,
},
// 模式 list列表 detail详情
mode: {
type: String,
default: 'list'
},
// 是否我自己 0不是 1是
isMine: {
type: [String, Number],
default: 0,
}
})
//
const emit = defineEmits(['showTime', 'showComment', 'showCollect', 'showShareFirend', 'onPlay', 'onPause', 'like', 'detailMenu', 'onEnd', 'longtap', 'update:item'])
// 视频上下文对象
const videoCtx = ref(null)
// 是否播放
const playState = ref(true)
// 是否显示快速收藏列表
const collectFirst = ref(false)
// 视频时间
const videoTime = reactive({
// 总长
duration: 0,
// 当前时间
currentTime: 0,
})
// 视频当前时间
let videoCurrentTime = ref(0)
// 设置时间
const alarmTime = computed(() => {
let result = uni.$store.state.alarmTime
return result
})
// 挂载后调用
onMounted(() => {
// 视频上下文对象
videoCtx.value = uni.createVideoContext(`video${props.tabIndex}${props.index}`)
})
// watch(playState, (nV) => {
// if (nV) play()
// else pause()
// })
/**
* 点击视频
*/
function handleVideo() {
// 根据播放状态切换播放暂停
if (playState.value) pause()
else play()
}
// 视频播放
function play() {
let pages = getCurrentPages();
let page = pages[pages.length - 1];
if (props.index != props.current || !['pages/index/index', 'pages/index/videoDetail'].includes(page.route)) return
videoCtx.value.play()
}
// 视频暂停
function pause() {
videoCtx.value.pause()
}
// 视频播放回调
function onVideoPlay() {
playState.value = true
emit('onPlay')
}
// 视频暂停回调
function onVideoPause() {
playState.value = false
emit('onPause')
}
// 打开评论
function handleComment() {
emit('showComment', props.item)
}
// 打开计时闹钟
function handleTime() {
emit('showTime')
}
// 打开收藏弹窗
function showCollect() {
util.isLogin().then(rs => {
emit('showCollect', props.item)
}).catch(() => {
uni.navigateTo({
url: '/pages/login/loginPhone'
})
})
}
// 切换快速收藏
function handleCollectFirst() {
return
collectFirst.value = !collectFirst.value
}
// 分享到好友
function handleShareFirend() {
util.isLogin().then(rs => {
emit('showShareFirend', props.item)
}).catch(() => {
uni.navigateTo({
url: '/pages/login/loginPhone'
})
})
}
/**
* 点赞
* @param {Number} index 操作的视频下标
* @param {Number|String} isLike 点赞操作
*/
function handleLike(index, isLike) {
console.log('index', index)
util.isLogin().then(rs => {
emit('like', {
index,
isLike,
})
}).catch(() => {
uni.navigateTo({
url: '/pages/login/loginPhone'
})
})
}
/**
* 私密赞
* @param {Object} index
*/
function handlePrivateLike(index) {
util.isLogin().then(rs => {
util.alert({
title: '提示',
content: '请确认,是否为隐私赞(隐私赞仅自己和作者可见)?',
confirmText: '隐私赞',
cancelText: '公开赞',
}).then(rs => {
if (rs.confirm) emit('like', {
index,
isLike: 3,
})
else emit('like', {
index,
isLike: 0
})
})
}).catch(() => {
uni.navigateTo({
url: '/pages/login/loginPhone'
})
})
}
/**
* 详情菜单
* @param {Object} item
*/
function handleDetailMenu(item) {
emit('detailMenu')
}
// 播放变化
function handleTimeupdate(ev) {
Object.assign(videoTime, ev.detail)
// 视频播放时长
if (videoTime.duration != 0) videoCurrentTime.value = videoTime.currentTime / videoTime.duration * 750
// console.log('update:item', {
// ...props.item,
// videoTime: videoTime,
// videoCurrentTime: videoCurrentTime.value,
// })
//
emit('update:item', {
...props.item,
videoTime: videoTime,
videoCurrentTime: videoCurrentTime.value,
})
}
// 视频播放结束
function handleEnded() {
videoCurrentTime.value = 750
videoCtx.value.stop()
setTimeout(() => {
if (props.index == props.current) play()
else pause()
}, 750)
// console.log('handleEnded', props.index, props.current)
// play()
emit('onEnd')
}
/**
* 查看用户主页
* @param {Object} item
*/
function handleUser(item) {
uni.navigateTo({
url: util.setUrl('/pages/index/videoHome', {
userId: item.userId
})
})
}
// 视频出现缓冲
function handleWaiting(ev) {
if (props.index == props.current) play()
else pause()
}
// 长按
function longtap(ev) {
emit('longtap')
}
//
defineExpose({
play,
pause,
videoTime,
item: props.item,
playState,
videoCtx: () => videoCtx.value,
})
</script>
<template>
<view class="f1 pr" ref="videoBoxRef">
<!-- 视频层 -->
<view class="videoBox pfull" @longpress="longtap" @touchmove.stop="">
<statusBar />
<video class="video f1" :id="'video' + tabIndex + index" :src="item.format_videoUrl" :show-fullscreen-btn="false" :enable-progress-gesture="false" controls="false" @click="handleVideo" @play="onVideoPlay" @pause="onVideoPause" :show-center-play-btn="false" @timeupdate="handleTimeupdate" @ended="handleEnded" @waiting="handleWaiting" :play-strategy="2" />
<!-- 视频进度条 -->
<!-- <videoProgress v-model:progress="videoCurrentTime" /> -->
<!-- 视频时长 -->
<!-- <view class="duration">
<view class="line" :style="{ width: videoCurrentTime + 'rpx' }"></view>
</view> -->
</view>
<!-- 暂停蒙版 -->
<view class="pausePanel pfull fmid" v-if="!playState">
<!-- 暂停按钮 -->
<image class="pauseImg" src="@/static/pause.png" mode="aspectFit" />
</view>
<!-- 右侧操作区 -->
<view class="panelRight pa t0 b0 r0">
<statusBar />
<view class="head"></view>
<view class="f1 jcr pl5 pt40 pr20">
<!-- 操作台 -->
<view class="operate f1">
<view class="item">
<view class="col">
<image class="wh60" src="@/static/statistics.jpg" mode="aspectFit" />
</view>
</view>
<!-- 用户头像 -->
<navigator :url="util.setUrl('/pages/index/videoHome',{userId:item.userId})" class="item pr mb10">
<view class="col">
<image class="wh80 cir" :src="item.format_header" mode="aspectFill" />
<view class="focus pa" v-if="!item.isAttention">
<image class="wh40" src="@/static/indexAtt.png" mode="aspectFit" />
</view>
</view>
</navigator>
<!-- 点赞 -->
<view class="item">
<view class="col">
<view class="pr">
<image class="wh50" src="/static/indexLike.png" mode="aspectFit" v-if="item.isLike == 0" @click="handleLike(index, 0)" @longpress="handlePrivateLike(index)" />
<image class="wh50" src="/static/indexLike1.png" mode="aspectFit" v-else-if="item.isLike == 1" @click="handleLike(index, 0)" />
<!-- 私密赞的图标 -->
<image class="wh50" src="/static/privateLike.png" mode="aspectFit" v-else-if="item.isLike == 3" @click="handleLike(index, 0)" />
</view>
<view class="txt mt10">
<text class="text">{{ item.likes }}</text>
</view>
</view>
</view>
<!-- 留言 -->
<view class="item" @click="handleComment">
<view class="col">
<image class="wh50" src="@/static/indexMsg.png" mode="aspectFit" />
<view class="txt mt10">
<text class="text">{{ item.comment }}</text>
</view>
</view>
</view>
<!-- 收藏 -->
<view class="item df fdr">
<view class="collectListBox" :class="{ 'active': collectFirst }">
<scroll-view scroll-x="true" :show-scrollbar="false" class="scroll df fdr">
<view class="list fdr plr15">
<template v-for="(item, index) in 5" :key="index">
<image class="li wh70 br20" src="/static/openPage.png" mode="aspectFill" />
</template>
</view>
</scroll-view>
</view>
<view class="col" @click="showCollect" @longpress="handleCollectFirst">
<image class="wh50" src="@/static/indexCollect1.png" mode="aspectFit" v-if="item.isCollect" />
<image class="wh50" src="@/static/indexCollect.png" mode="aspectFit" v-else />
<view class="txt mt10">
<text class="text">{{ item.collect }}</text>
</view>
</view>
</view>
<!-- 分享 -->
<view class="item" @click="handleShareFirend">
<view class="col">
<image class="wh50" src="@/static/indexShare.png" mode="aspectFit" />
<view class="txt mt10">
<text class="text">分享</text>
</view>
</view>
</view>
<!-- 闹钟 -->
<view class="item money" @click="handleTime" v-if="mode == 'list'">
<view class="col">
<image class="wh80" src="/static/indexMoney1.png" mode="aspectFit" v-if="alarmTime" />
<image class="wh80" src="/static/indexMoney.png" mode="aspectFit" v-else />
</view>
</view>
<!-- 详情菜单 -->
<view class="item money" @click="handleTime" v-if="mode == 'detail' && isMine == 1">
<view class="col wh90 fmid tac" @click="handleDetailMenu">
<uni-icons type="more-filled" color="#d8d8d8" size="70rpx" />
</view>
</view>
</view>
</view>
</view>
<!-- 底部用户信息 -->
<view class="panelBottom pa l0 r0 b0 pl40 pb30">
<!-- 商品信息 -->
<view class="goods df fdr mb20 br10" v-if="0">
<!-- 商品图片 -->
<image class="image wh100 mr15 br10" src="/static/openPage.png" mode="aspectFill" />
<view class="df fdc jcsb f1">
<view class="">
<text class="cfff f28">果农大王霹雳美味榴莲果子</text>
</view>
<view class="info df fdr aic mr10">
<text class="price mr10 cfff f28 b">超低价6.66</text>
<text class="cfff f1 f20">已售666</text>
<uni-icons type="close" color="#fff" />
</view>
</view>
</view>
<!-- 用户 -->
<view class="user" @click="handleUser(item)">
<text class="cfff f36">@{{ item.userName }}</text>
</view>
<!-- 简介 -->
<view class="desc mt5">
<text class="t2hd cfff f28">{{ item.title }}</text>
</view>
</view>
</view>
</template>
<style lang="scss">
// 视频盒子
.videoBox {
background-color: #000;
}
// 视频时长
.duration {
margin-top: 120rpx;
width: 750rpx;
background-color: rgba(255, 255, 255, .3);
// 时间时长
.line {
width: 0;
height: 2rpx;
background-color: rgba(255, 255, 255, .8);
transition-duration: .25s;
}
}
// 暂停蒙层
.pausePanel {
background-color: rgba(0, 0, 0, .5);
//
.pauseImg {
width: 140rpx;
height: 140rpx;
}
}
// 右侧屏幕
.panelRight {
align-items: flex-end;
.text {
text-align: center;
color: #fff;
font-size: 24rpx;
}
// 操作台
.operate {
flex: 1;
justify-content: flex-end;
align-items: flex-end;
text-align: center;
padding-bottom: 130rpx;
.item {
margin: 5rpx 0;
padding: 10rpx 5rpx;
&.money {
padding: 0;
}
//
.col {
align-items: center;
justify-content: center;
width: 80rpx;
}
}
}
// 关注的小加号
.focus {
align-items: center;
left: 0;
right: 0;
bottom: 0;
}
}
// 底部
.panelBottom {
padding-right: 150rpx;
//
.goods {
padding: 10rpx;
width: 480rpx;
margin-bottom: 20rpx;
background-color: rgba(0, 0, 0, .3);
}
}
// 收藏列表盒子
.collectListBox {
justify-content: center;
width: 0;
background-color: rgba(51, 51, 51, .5);
border-radius: 25rpx;
transition-property: width;
transition-duration: .3s;
// 激活的
&.active {
width: 300rpx;
}
.li+.li {
margin-left: 15rpx;
}
}
</style>