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