jiuyiUniapp/jiuyi2/components/index/indexVideo.vue

549 lines
12 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<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>