549 lines
12 KiB
Vue
549 lines
12 KiB
Vue
<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> |